Files
imbad0202__academic-researc…/scripts/test_inquiry_branch_ledger.py
T
Edward Cheng-I Wu f1a57bbcab fix: shared file-lock helper with msvcrt backend for the remaining fcntl sites (#845) (#847)
* fix: shared file-lock helper with msvcrt backend for the six fcntl sites (#845)

scripts/file_lock.py owns the backend choice (fcntl.flock on POSIX,
msvcrt.locking on byte 0 on Windows) and routes adjudication_activity,
inquiry_branch_ledger, review_criteria_binding, and ars_mark_read through
acquire()/release(). POSIX lock sequences are unchanged. Per-site Windows
decisions: adjudication reads degrade to exclusive with a 5 s bounded wait;
the review-criteria manifest lock is capped at 30 s on Windows only; the
inquiry ledger alpha keeps refusing non-POSIX hosts. Two finally blocks that
released an unacquired lock now release only what they acquired. SETUP docs
state the best-effort Windows posture; no Windows CI job is added.

Refs #845, #843, #844.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2

* fix(file_lock): interrupted attempts honour the deadline; pin adjudication wait policy (#845)

Cross-model review round 1 (gpt-6-astra, xhigh): a persistent
InterruptedError could retry past the bound; the Windows-shape test did
not exercise adjudication's reader-waits / writer-does-not-wait policy;
the adjudication contention message now names LockTimeout instead of
BlockingIOError, recorded in the CHANGELOG rather than masked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2

* refactor(file_lock): held() context manager, single BACKEND source, one fake msvcrt (#845)

/simplify pass (four cleanup reviewers): the release-only-if-acquired
invariant moves into file_lock.held() and review_criteria_binding /
inquiry_branch_ledger use it; runtime branches key off BACKEND and
SHARED_LOCKS_SUPPORTED is dropped; EINTR joins the retryable errno set and
the unreachable EDEADLK entry goes; backend calls are deduplicated; all four
consumers try the sibling import first so one module instance is shared;
the Windows fake lives once in tests/fake_msvcrt.py; test scaffolding is
folded into a lock_pair fixture and a parametrized wait test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2

* fix(file_lock): keep lock acquisition and the guarded body in separate try blocks (#845)

Cross-model review round 3 (gpt-6-astra, xhigh): wrapping the body in the
same handler that translates LockTimeout meant a contended inner lock inside
the body was reported as the outer manifest/passport lock failing. Both
consumers now acquire in their own try block and release only after a
successful acquire; held() is dropped from the helper. The subprocess test
pins that a LockTimeout raised inside the binding body surfaces as itself.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2

* test(file_lock): let the body LockTimeout leave _locked() so the attribution check bites (#845)

Cross-model review round 4: the inner LockTimeout was caught inside the
binding body, so the erroneous outer translation would still have passed.
Verified by mutation: restoring the outer translation fails this test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2

* ci(673): whitelist scripts/test_file_lock.py as a non-consumer importer of the activity runtime (#845)

The shared file-lock test imports adjudication_activity in a subprocess to
exercise its lock backend under a fake msvcrt; it never reads or writes an
activity store. The exact-owner whitelist is the lint's route for that.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:47:26 +08:00

2294 lines
74 KiB
Python

#!/usr/bin/env python3
"""Hermetic contract/replay/storage tests for inquiry-branch-ledger/1.0 (#743)."""
from __future__ import annotations
import copy
import hashlib
import json
import os
import stat
import subprocess
import sys
from pathlib import Path
import pytest
from jsonschema import Draft202012Validator, FormatChecker
from scripts.inquiry_branch_ledger import (
ENV_FLAG,
ContractError,
LedgerBindingError,
TransactionRecoveryError,
append_event,
canonical_bytes,
checkpoint_summary,
commit_ledger_transaction,
default_ledger_relative_path,
inquiry_ledger_enabled,
load_bound_ledger,
load_ledger,
new_ledger,
recover_ledger_transaction,
render_summary,
replay_ledger,
validate_ledger_shape,
validate_pointer,
)
from scripts.research_workflow_profile import (
DEFAULT_FIELD_GENERAL_PROFILE,
load_profile,
seal_profile,
)
from scripts import file_lock
REPO_ROOT = Path(__file__).resolve().parent.parent
LEDGER_SCHEMA = (
REPO_ROOT
/ "shared"
/ "contracts"
/ "research_workflow"
/ "inquiry_branch_ledger.schema.json"
)
POINTER_SCHEMA = (
REPO_ROOT / "shared" / "contracts" / "passport" / "inquiry_ledger_ref.schema.json"
)
RUNTIME = REPO_ROOT / "scripts" / "inquiry_branch_ledger.py"
def _profile(*, profile_id: str = "field_general", branch_budget: int = 3) -> dict:
profile = copy.deepcopy(load_profile(DEFAULT_FIELD_GENERAL_PROFILE))
if profile_id != "field_general" or branch_budget != 3:
profile.update(
{
"profile_id": profile_id,
"branch_budget": branch_budget,
"provenance": {
"source": "user_modified",
"source_pointer": f"synthetic test profile: {profile_id}",
"last_reviewed_at": "2026-08-24",
"freshness_state": "unverified",
},
}
)
profile = seal_profile(profile)
return profile
def _event(
kind: str,
branch_id: str | None,
payload: dict,
*,
actor: str = "author",
minute: int = 0,
) -> dict:
return {
"recorded_at": f"2026-08-24T10:{minute:02d}:00+08:00",
"actor": actor,
"kind": kind,
"branch_id": branch_id,
"payload": payload,
}
def _created_payload(
statement: str,
*,
parent_id: str | None = None,
refs: list[str] | None = None,
conditions: list[dict] | None = None,
) -> dict:
return {
"parent_id": parent_id,
"statement": statement,
"assumptions": [],
"evidence_sought": [],
"reopen_conditions": [] if conditions is None else conditions,
"downstream_refs": [] if refs is None else refs,
}
def _two_branch_ledger(profile: dict | None = None) -> tuple[dict, dict]:
profile = profile or _profile()
ledger = new_ledger("project-alpha", profile)
ledger = append_event(
ledger,
_event(
"branch_created",
"main",
_created_payload(
"Primary framing",
refs=["draft-v1", "shared-table"],
conditions=[
{
"condition_id": "invariance-fails",
"statement": "Reopen if measurement invariance fails",
}
],
),
),
[profile],
)
ledger = append_event(
ledger,
_event(
"facet_surfaced",
"facet",
{"parent_id": "main", "surfaced_text": "Alternative mechanism"},
actor="ai",
minute=1,
),
[profile],
)
return ledger, profile
def _adopt_facet(ledger: dict, profiles) -> dict:
return append_event(
ledger,
_event(
"branch_adopted",
"facet",
{
"source_event_id": 2,
"surfaced_text": "Alternative mechanism",
"author_formulation": "Author-owned alternative mechanism",
},
minute=2,
),
profiles,
)
def _write_canonical(path: Path, value: dict) -> Path:
path.write_bytes(canonical_bytes(value))
return path
def _passport(path: Path) -> Path:
path.write_text(
"# keep this comment\n"
"origin_skill: academic-paper\n"
"origin_mode: full\n"
"verification_status: UNVERIFIED\n"
"version_label: v1\n",
encoding="utf-8",
)
return path
def _append_raw_event(ledger: dict, event_input: dict) -> dict:
"""Test-only chain completion for malformed semantic histories."""
updated = copy.deepcopy(ledger)
events = updated["events"]
events.append(
{
"event_id": len(events) + 1,
**event_input,
"prev_event_sha256": (
"0" * 64
if not events
else hashlib.sha256(canonical_bytes(events[-1])).hexdigest()
),
}
)
return updated
def _leave_update_journal(tmp_path: Path) -> tuple[Path, Path, Path, dict, dict]:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
ledger_path = tmp_path / "passport.inquiry-branch-ledger.json"
commit_ledger_transaction(
passport, ledger_path, tmp_path, ledger, [profile], "project-alpha"
)
updated = _adopt_facet(ledger, [profile])
def crash(phase: str) -> None:
if phase == "journal_durable":
raise RuntimeError("leave journal")
with pytest.raises(RuntimeError, match="leave journal"):
commit_ledger_transaction(
passport,
ledger_path,
tmp_path,
updated,
[profile],
"project-alpha",
crash_hook=crash,
)
journal = tmp_path / ".passport.yaml.inquiry-ledger.transaction.json"
assert journal.is_file()
return passport, ledger_path, journal, updated, profile
# ---------------------------------------------------------------------------
# JSON Schemas + closed shape
# ---------------------------------------------------------------------------
def test_schemas_compile_and_accept_runtime_artifacts() -> None:
ledger, profile = _two_branch_ledger()
ledger_schema = json.loads(LEDGER_SCHEMA.read_text(encoding="utf-8"))
pointer_schema = json.loads(POINTER_SCHEMA.read_text(encoding="utf-8"))
Draft202012Validator.check_schema(ledger_schema)
Draft202012Validator.check_schema(pointer_schema)
ledger_validator = Draft202012Validator(
ledger_schema, format_checker=FormatChecker()
)
pointer_validator = Draft202012Validator(pointer_schema)
assert list(ledger_validator.iter_errors(ledger)) == []
pointer = {
"ledger_path": "project.inquiry-branch-ledger.json",
"ledger_version": "inquiry-branch-ledger/1.0",
"content_sha256": hashlib.sha256(canonical_bytes(ledger)).hexdigest(),
}
assert list(pointer_validator.iter_errors(pointer)) == []
replay_ledger(ledger, [profile], require_materialized=True)
@pytest.mark.parametrize(
"mutation",
[
lambda ledger: ledger.update({"projection": {}}),
lambda ledger: ledger["events"][0].update({"unknown": True}),
lambda ledger: ledger["events"][0]["payload"].update({"patch": []}),
lambda ledger: ledger["events"][0].update({"actor": "ai"}),
lambda ledger: ledger["events"][0].update({"branch_id": None}),
],
)
def test_schema_and_runtime_reject_closed_shape_mutations(mutation) -> None:
ledger, profile = _two_branch_ledger()
mutation(ledger)
schema = json.loads(LEDGER_SCHEMA.read_text(encoding="utf-8"))
assert list(Draft202012Validator(schema).iter_errors(ledger))
with pytest.raises(ContractError):
replay_ledger(ledger, [profile])
def test_pointer_schema_and_runtime_reject_escape_and_unknown_fields() -> None:
schema = json.loads(POINTER_SCHEMA.read_text(encoding="utf-8"))
validator = Draft202012Validator(schema)
base = {
"ledger_path": "../escape.json",
"ledger_version": "inquiry-branch-ledger/1.0",
"content_sha256": "a" * 64,
"extra": True,
}
assert list(validator.iter_errors(base))
with pytest.raises(ContractError):
validate_pointer(base)
del base["extra"]
with pytest.raises(ContractError, match=r"workspace-relative|\.\."):
validate_pointer(base)
@pytest.mark.parametrize(
"ledger_path",
[
r"nested\\ledger.json",
"./ledger.json",
"nested/../ledger.json",
"nested//ledger.json",
"nested/",
"nested/ledger\u0007.json",
"nested/ledger\u202e.json",
],
)
def test_pointer_schema_and_runtime_share_normalized_path_grammar(
ledger_path: str,
) -> None:
schema = json.loads(POINTER_SCHEMA.read_text(encoding="utf-8"))
pointer = {
"ledger_path": ledger_path,
"ledger_version": "inquiry-branch-ledger/1.0",
"content_sha256": "a" * 64,
}
assert list(Draft202012Validator(schema).iter_errors(pointer))
with pytest.raises(ContractError):
validate_pointer(pointer)
def test_schema_and_runtime_share_frozen_free_text_and_optional_reopen_shape() -> None:
profile = _profile()
ledger = new_ledger("project-alpha", profile)
ledger = append_event(
ledger,
_event(
"branch_created",
"main",
{
"parent_id": None,
"statement": "Main",
"assumptions": ["same", "same"],
"evidence_sought": ["same", "same"],
"reopen_conditions": [
{
"condition_id": "measurement condition 1",
"statement": "Reopen on failed invariance",
}
],
"downstream_refs": [],
},
),
[profile],
)
ledger = append_event(
ledger,
_event(
"facet_surfaced",
"facet",
{"parent_id": "main", "surfaced_text": "Facet"},
actor="ai",
minute=1,
),
[profile],
)
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "wait"}, minute=2),
[profile],
)
ledger = append_event(
ledger,
_event(
"branch_reopened",
"main",
{"reason": "condition met", "condition_id": "measurement condition 1"},
minute=3,
),
[profile],
)
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "wait again"}, minute=4),
[profile],
)
ledger = append_event(
ledger,
_event(
"branch_reopened",
"main",
{"reason": "other evidence", "evidence_pointer": "results#secondary"},
minute=5,
),
[profile],
)
schema = json.loads(LEDGER_SCHEMA.read_text(encoding="utf-8"))
assert list(
Draft202012Validator(schema, format_checker=FormatChecker()).iter_errors(
ledger
)
) == []
replay_ledger(ledger, [profile], require_materialized=True)
def test_schema_and_runtime_reject_leading_zero_semver_identifier() -> None:
ledger, profile = _two_branch_ledger()
ledger["initial_profile_binding"]["profile_version"] = "1.0.0-01"
schema = json.loads(LEDGER_SCHEMA.read_text(encoding="utf-8"))
assert list(Draft202012Validator(schema).iter_errors(ledger))
with pytest.raises(ContractError, match="SemVer"):
replay_ledger(ledger, [profile])
def test_duplicate_json_keys_and_noncanonical_storage_fail(tmp_path: Path) -> None:
duplicate = tmp_path / "duplicate.json"
duplicate.write_text(
'{"schema_version":"inquiry-branch-ledger/1.0",'
'"schema_version":"inquiry-branch-ledger/1.0"}',
encoding="utf-8",
)
with pytest.raises(ContractError, match="duplicate JSON key"):
load_ledger(duplicate)
ledger, _ = _two_branch_ledger()
pretty = tmp_path / "pretty.json"
pretty.write_text(json.dumps(ledger, indent=2), encoding="utf-8")
with pytest.raises(ContractError, match="exact JSON Canonical Form"):
load_ledger(pretty)
def test_schema_and_runtime_share_frozen_non_slug_condition_and_list_domain() -> None:
"""Only branch ids are frozen as slugs; ordinary text lists are lists."""
profile = _profile()
ledger = new_ledger("project-alpha", profile)
ledger = append_event(
ledger,
_event(
"branch_created",
"main",
{
**_created_payload(
"Main",
conditions=[
{
"condition_id": "Condition 1 / confirmatory",
"statement": "Reopen on contrary evidence",
}
],
),
"assumptions": ["same text", "same text"],
"evidence_sought": ["same source", "same source"],
},
),
[profile],
)
ledger = append_event(
ledger,
_event(
"facet_surfaced",
"facet",
{"parent_id": "main", "surfaced_text": "Facet"},
actor="ai",
minute=1,
),
[profile],
)
replay_ledger(ledger, [profile], require_materialized=True)
schema = json.loads(LEDGER_SCHEMA.read_text(encoding="utf-8"))
assert list(Draft202012Validator(schema).iter_errors(ledger)) == []
@pytest.mark.parametrize(
"reopen_payload",
[
{"reason": "stored condition", "condition_id": "invariance-fails"},
{"reason": "uncatalogued evidence", "evidence_pointer": "results#row-2"},
],
)
def test_schema_and_runtime_allow_each_optional_reopen_field_independently(
reopen_payload: dict,
) -> None:
ledger, profile = _two_branch_ledger()
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "wait"}, minute=2),
[profile],
)
ledger = append_event(
ledger,
_event("branch_reopened", "main", reopen_payload, minute=3),
[profile],
)
replay_ledger(ledger, [profile])
schema = json.loads(LEDGER_SCHEMA.read_text(encoding="utf-8"))
assert list(Draft202012Validator(schema).iter_errors(ledger)) == []
def test_schema_and_runtime_share_strict_semver_domain() -> None:
ledger, _ = _two_branch_ledger()
ledger["initial_profile_binding"]["profile_version"] = "1.0.0-01"
with pytest.raises(ContractError, match="SemVer"):
validate_ledger_shape(ledger)
schema = json.loads(LEDGER_SCHEMA.read_text(encoding="utf-8"))
assert list(Draft202012Validator(schema).iter_errors(ledger))
@pytest.mark.parametrize(
"unsafe_path",
["folder\\ledger.json", "folder/./ledger.json", "folder//ledger.json", "folder/"],
)
def test_pointer_schema_and_runtime_share_normalized_posix_path_domain(
unsafe_path: str,
) -> None:
pointer = {
"ledger_path": unsafe_path,
"ledger_version": "inquiry-branch-ledger/1.0",
"content_sha256": "a" * 64,
}
with pytest.raises(ContractError, match="normalized"):
validate_pointer(pointer)
schema = json.loads(POINTER_SCHEMA.read_text(encoding="utf-8"))
assert list(Draft202012Validator(schema).iter_errors(pointer))
# ---------------------------------------------------------------------------
# State machine, provenance, conditions, and budget
# ---------------------------------------------------------------------------
def test_full_lawful_transition_history_replays_deterministically() -> None:
ledger, profile = _two_branch_ledger()
ledger = _adopt_facet(ledger, [profile])
for minute, field, value in (
(3, "assumptions", ["measurement is comparable"]),
(4, "evidence_sought", ["invariance test"]),
(
5,
"reopen_conditions",
[
{
"condition_id": "invariance-fails",
"statement": "Reopen if measurement invariance fails",
"evidence_pointer": "analysis-plan#invariance",
}
],
),
(6, "downstream_refs", ["draft-v1", "table-v1"]),
):
ledger = append_event(
ledger,
_event(
"branch_annotated",
"main",
{"field": field, "value": value},
minute=minute,
),
[profile],
)
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "await evidence"}, minute=7),
[profile],
)
ledger = append_event(
ledger,
_event(
"reopen_condition_signal",
"main",
{
"branch_id_ref": "main",
"condition_id": "invariance-fails",
"evidence_pointer": "results#table-2",
},
actor="ai",
minute=8,
),
[profile],
)
ledger = append_event(
ledger,
_event(
"branch_reopened",
"main",
{
"reason": "author judges condition satisfied",
"condition_id": "invariance-fails",
"evidence_pointer": "results#table-2",
},
minute=9,
),
[profile],
)
first = replay_ledger(ledger, [profile], require_materialized=True)
second = replay_ledger(
json.loads(canonical_bytes(ledger)), [profile], require_materialized=True
)
assert first == second
main = first["branches"][0]
assert main["status"] == "reopened"
assert main["assumptions"] == ["measurement is comparable"]
assert main["evidence_sought"] == ["invariance test"]
assert [row["artifact_ref"] for row in first["artifacts"]] == [
"draft-v1",
"table-v1",
]
assert all(row["stale"] for row in first["artifacts"])
assert first["reopen_condition_signals"][0]["condition_statement"].startswith(
"Reopen if"
)
def test_ai_facet_requires_origin_bound_substantive_adoption() -> None:
ledger, profile = _two_branch_ledger()
mutations = [
{
"source_event_id": 1,
"surfaced_text": "Alternative mechanism",
"author_formulation": "Author alternative",
},
{
"source_event_id": 2,
"surfaced_text": "changed",
"author_formulation": "Author alternative",
},
{
"source_event_id": 2,
"surfaced_text": "Alternative mechanism",
"author_formulation": "Alternative mechanism",
},
{
"source_event_id": 2,
"surfaced_text": "Alternative mechanism",
"author_formulation": " OK ",
},
]
for payload in mutations:
with pytest.raises(ContractError):
append_event(
ledger,
_event("branch_adopted", "facet", payload, minute=2),
[profile],
)
adopted = _adopt_facet(ledger, [profile])
branch = replay_ledger(adopted, [profile])["branches"][1]
assert branch["provenance"] == "author_adopted"
assert branch["adoption_receipt"]["source_event_id"] == 2
assert branch["surfaced_text"] == "Alternative mechanism"
assert branch["statement"] == "Author-owned alternative mechanism"
def test_unadopted_facet_reopen_and_post_rejection_events_fail() -> None:
ledger, profile = _two_branch_ledger()
with pytest.raises(ContractError, match="unadopted"):
append_event(
ledger,
_event("branch_reopened", "facet", {"reason": "try"}, minute=2),
[profile],
)
rejected = append_event(
ledger,
_event("branch_rejected", "facet", {"reason": "not adopted"}, minute=2),
[profile],
)
for kind, payload in (
("branch_archived", {"reason": "archive"}),
(
"branch_adopted",
{
"source_event_id": 2,
"surfaced_text": "Alternative mechanism",
"author_formulation": "Changed mind",
},
),
):
with pytest.raises(ContractError, match="terminal|parked"):
append_event(rejected, _event(kind, "facet", payload, minute=3), [profile])
def test_condition_identity_is_immutable_and_removed_ids_are_retired() -> None:
ledger, profile = _two_branch_ledger()
changed = _event(
"branch_annotated",
"main",
{
"field": "reopen_conditions",
"value": [
{
"condition_id": "invariance-fails",
"statement": "Different condition text",
}
],
},
minute=2,
)
with pytest.raises(ContractError, match="cannot be rebound"):
append_event(ledger, changed, [profile])
removed = append_event(
ledger,
_event(
"branch_annotated",
"main",
{"field": "reopen_conditions", "value": []},
minute=2,
),
[profile],
)
with pytest.raises(ContractError, match="retired"):
append_event(
removed,
_event(
"branch_annotated",
"main",
{
"field": "reopen_conditions",
"value": [
{
"condition_id": "invariance-fails",
"statement": "Reopen if measurement invariance fails",
}
],
},
minute=3,
),
[profile],
)
with pytest.raises(ContractError, match="currently stored"):
append_event(
removed,
_event(
"reopen_condition_signal",
"main",
{
"branch_id_ref": "main",
"condition_id": "invariance-fails",
"evidence_pointer": "row",
},
actor="ai",
minute=3,
),
[profile],
)
def test_unknown_parent_duplicate_branch_and_terminal_mutation_fail() -> None:
profile = _profile()
ledger = new_ledger("project-alpha", profile)
with pytest.raises(ContractError, match="earlier event"):
append_event(
ledger,
_event(
"branch_created",
"child",
_created_payload("Child", parent_id="missing"),
),
[profile],
)
ledger, _ = _two_branch_ledger(profile)
with pytest.raises(ContractError, match="cannot be reused"):
append_event(
ledger,
_event("branch_created", "main", _created_payload("Again"), minute=2),
[profile],
)
archived = append_event(
ledger,
_event("branch_archived", "main", {"reason": "closed"}, minute=2),
[profile],
)
with pytest.raises(ContractError, match="terminal"):
append_event(
archived,
_event(
"branch_annotated",
"main",
{"field": "assumptions", "value": ["late"]},
minute=3,
),
[profile],
)
def test_budget_allows_parked_facet_but_blocks_adoption_and_creation() -> None:
profile = _profile(profile_id="budget-one", branch_budget=1)
ledger, _ = _two_branch_ledger(profile)
assert replay_ledger(ledger, [profile])["live_count"] == 1
with pytest.raises(ContractError, match="branch_budget"):
_adopt_facet(ledger, [profile])
with pytest.raises(ContractError, match="branch_budget"):
append_event(
ledger,
_event("branch_created", "second", _created_payload("Second"), minute=2),
[profile],
)
parked = append_event(
ledger,
_event("branch_parked", "main", {"reason": "make room"}, minute=2),
[profile],
)
adopted = _adopt_facet(parked, [profile])
assert replay_ledger(adopted, [profile])["live_count"] == 1
def test_profile_rebound_requires_exact_catalog_and_prior_disposition() -> None:
ledger, wide = _two_branch_ledger()
ledger = _adopt_facet(ledger, [wide])
narrow = _profile(profile_id="narrow", branch_budget=1)
payload = {
"profile_id": narrow["profile_id"],
"profile_version": narrow["profile_version"],
"content_sha256": narrow["content_sha256"],
"selection_receipt_ref": "receipts/profile-selection.json",
}
with pytest.raises(ContractError, match="unresolved"):
append_event(
ledger,
_event("profile_rebound", None, payload, minute=3),
[wide],
)
with pytest.raises(ContractError, match="dispose live branches"):
append_event(
ledger,
_event("profile_rebound", None, payload, minute=3),
[wide, narrow],
)
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "lower budget"}, minute=3),
[wide],
)
rebound = append_event(
ledger,
_event("profile_rebound", None, payload, minute=4),
[wide, narrow],
)
projection = replay_ledger(rebound, [wide, narrow])
assert projection["effective_profile_binding"] == {
key: narrow[key] for key in ("profile_id", "profile_version", "content_sha256")
}
assert projection["branch_budget"] == 1
def test_event_order_is_ids_not_timestamp_monotonicity() -> None:
ledger, profile = _two_branch_ledger()
ledger["events"][1]["recorded_at"] = "2026-08-23T00:00:00Z"
# recorded_at is deliberately not part of the ordering rule. Event 2's
# own change does not affect its prev hash, and there is no event 3.
assert replay_ledger(ledger, [profile])["event_count"] == 2
# ---------------------------------------------------------------------------
# Hash chain, invalidation causes, merge, and supersession
# ---------------------------------------------------------------------------
def test_dense_ids_and_previous_event_hash_are_fail_closed() -> None:
ledger, profile = _two_branch_ledger()
bad_id = copy.deepcopy(ledger)
bad_id["events"][1]["event_id"] = 3
with pytest.raises(ContractError, match="dense event id 2"):
replay_ledger(bad_id, [profile])
changed_interior = copy.deepcopy(ledger)
changed_interior["events"][0]["payload"]["statement"] = "rewritten"
with pytest.raises(ContractError, match="previous event"):
replay_ledger(changed_interior, [profile])
def test_truncation_needs_materialization_or_passport_head_to_detect() -> None:
ledger, profile = _two_branch_ledger()
truncated = copy.deepcopy(ledger)
truncated["events"] = truncated["events"][:1]
# Chain alone has no later edge and therefore accepts a well-formed prefix.
assert replay_ledger(truncated, [profile])["event_count"] == 1
with pytest.raises(ContractError, match="at least two"):
replay_ledger(truncated, [profile], require_materialized=True)
def test_reopen_auto_emits_contiguous_ordered_stale_events() -> None:
ledger, profile = _two_branch_ledger()
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "wait"}, minute=2),
[profile],
)
reopened = append_event(
ledger,
_event("branch_reopened", "main", {"reason": "new evidence"}, minute=3),
[profile],
)
assert [event["kind"] for event in reopened["events"][-3:]] == [
"branch_reopened",
"artifact_marked_stale",
"artifact_marked_stale",
]
assert [event["payload"]["artifact_ref"] for event in reopened["events"][-2:]] == [
"draft-v1",
"shared-table",
]
assert all(event["actor"] == "system" for event in reopened["events"][-2:])
missing = copy.deepcopy(reopened)
missing["events"].pop()
with pytest.raises(ContractError, match="ends before"):
replay_ledger(missing, [profile])
reordered = copy.deepcopy(reopened)
first, second = reordered["events"][-2:]
reordered["events"][-2:] = [second, first]
# Repair chain links so the failure specifically exercises stale ordering.
for index in range(len(reordered["events"])):
reordered["events"][index]["event_id"] = index + 1
reordered["events"][index]["prev_event_sha256"] = (
"0" * 64
if index == 0
else hashlib.sha256(canonical_bytes(reordered["events"][index - 1])).hexdigest()
)
with pytest.raises(ContractError, match="downstream_refs order"):
replay_ledger(reordered, [profile])
def test_direct_or_orphan_stale_event_is_refused() -> None:
ledger, profile = _two_branch_ledger()
raw = _event(
"artifact_marked_stale",
None,
{"artifact_ref": "draft-v1", "reopening_event_id": 1},
actor="system",
minute=2,
)
with pytest.raises(ContractError, match="mechanically"):
append_event(ledger, raw, [profile])
malformed = _append_raw_event(ledger, raw)
with pytest.raises(ContractError, match="orphan"):
replay_ledger(malformed, [profile])
def test_two_stale_causes_clear_independently() -> None:
profile = _profile()
ledger = new_ledger("project-alpha", profile)
for minute, branch_id in enumerate(("a", "b")):
ledger = append_event(
ledger,
_event(
"branch_created",
branch_id,
_created_payload(branch_id.upper(), refs=["shared"]),
minute=minute,
),
[profile],
)
for minute, branch_id in ((2, "a"), (4, "b")):
ledger = append_event(
ledger,
_event("branch_parked", branch_id, {"reason": "wait"}, minute=minute),
[profile],
)
ledger = append_event(
ledger,
_event(
"branch_reopened", branch_id, {"reason": "evidence"}, minute=minute + 1
),
[profile],
)
projection = replay_ledger(ledger, [profile])
causes = projection["artifacts"][0]["outstanding_stale_causes"]
assert len(causes) == 2
ledger = append_event(
ledger,
_event(
"artifact_reconfirmed",
None,
{
"artifact_ref": "shared",
"resolves_stale_event_id": causes[0],
"note": "valid for branch a",
},
minute=6,
),
[profile],
)
artifact = replay_ledger(ledger, [profile])["artifacts"][0]
assert artifact["stale"] is True
assert artifact["outstanding_stale_causes"] == [causes[1]]
ledger = append_event(
ledger,
_event(
"artifact_reconfirmed",
None,
{
"artifact_ref": "shared",
"resolves_stale_event_id": causes[1],
"note": "valid for branch b",
},
minute=7,
),
[profile],
)
artifact = replay_ledger(ledger, [profile])["artifacts"][0]
assert artifact["stale"] is False
assert len(artifact["resolution_history"]) == 2
with pytest.raises(ContractError, match="already been resolved"):
append_event(
ledger,
_event(
"artifact_reconfirmed",
None,
{
"artifact_ref": "shared",
"resolves_stale_event_id": causes[0],
"note": "duplicate",
},
minute=8,
),
[profile],
)
def test_merge_order_and_supersession_update_every_branch() -> None:
profile = _profile()
ledger = new_ledger("project-alpha", profile)
ledger = append_event(
ledger,
_event(
"branch_created",
"target",
_created_payload("Target", refs=["a", "shared"]),
),
[profile],
)
ledger = append_event(
ledger,
_event(
"branch_created",
"source",
_created_payload("Source", refs=["shared", "b"]),
minute=1,
),
[profile],
)
ledger = append_event(
ledger,
_event(
"branch_merged",
"source",
{"merged_into": "target", "reason": "combine"},
minute=2,
),
[profile],
)
projection = replay_ledger(ledger, [profile])
assert projection["branches"][0]["downstream_refs"] == ["a", "shared", "b"]
assert projection["branches"][1]["status"] == "merged"
ledger = append_event(
ledger,
_event("branch_parked", "target", {"reason": "wait"}, minute=3),
[profile],
)
ledger = append_event(
ledger,
_event("branch_reopened", "target", {"reason": "new"}, minute=4),
[profile],
)
projection = replay_ledger(ledger, [profile])
cause = next(
row["outstanding_stale_causes"][0]
for row in projection["artifacts"]
if row["artifact_ref"] == "shared"
)
ledger = append_event(
ledger,
_event(
"artifact_superseded",
None,
{
"artifact_ref": "shared",
"resolves_stale_event_id": cause,
"note": "replaced",
"replaced_by": "shared-v2",
},
minute=5,
),
[profile],
)
branches = replay_ledger(ledger, [profile])["branches"]
assert branches[0]["downstream_refs"] == ["a", "shared-v2", "b"]
assert branches[1]["downstream_refs"] == ["shared-v2", "b"]
def test_merge_requires_distinct_live_target() -> None:
ledger, profile = _two_branch_ledger()
ledger = _adopt_facet(ledger, [profile])
with pytest.raises(ContractError, match="itself"):
append_event(
ledger,
_event(
"branch_merged",
"main",
{"merged_into": "main", "reason": "self"},
minute=3,
),
[profile],
)
parked = append_event(
ledger,
_event("branch_parked", "facet", {"reason": "not live"}, minute=3),
[profile],
)
with pytest.raises(ContractError, match="currently-live"):
append_event(
parked,
_event(
"branch_merged",
"main",
{"merged_into": "facet", "reason": "bad target"},
minute=4,
),
[profile],
)
# ---------------------------------------------------------------------------
# Pointer authority, default-off behavior, and transaction recovery
# ---------------------------------------------------------------------------
def test_default_flag_and_simple_path_are_silent() -> None:
assert inquiry_ledger_enabled({}) is False
assert inquiry_ledger_enabled({ENV_FLAG: "0"}) is False
assert inquiry_ledger_enabled({ENV_FLAG: "true"}) is False
assert inquiry_ledger_enabled({ENV_FLAG: "1"}) is True
profile = _profile()
one = new_ledger("project-alpha", profile)
one = append_event(
one,
_event("branch_created", "main", _created_payload("Main")),
[profile],
)
projection = replay_ledger(one, [profile])
assert checkpoint_summary(
projection, moment="design_freeze", env={ENV_FLAG: "1"}
) is None
two, profile = _two_branch_ledger(profile)
projection = replay_ledger(two, [profile])
assert checkpoint_summary(projection, moment="stage_2_5", env={}) is None
rendered = checkpoint_summary(
projection, moment="stage_4_5", env={ENV_FLAG: "1"}
)
assert rendered is not None
assert "main [active; author_originated]" in rendered
assert "parked=1" in rendered
assert "archived" not in rendered
assert "skip | off | reset-to-simple-path" in rendered
def test_signal_summary_names_parked_branch_for_author_judgment() -> None:
ledger, profile = _two_branch_ledger()
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "await evidence"}, minute=2),
[profile],
)
ledger = append_event(
ledger,
_event(
"reopen_condition_signal",
"main",
{
"branch_id_ref": "main",
"condition_id": "invariance-fails",
"evidence_pointer": "result-row-7",
},
actor="ai",
minute=3,
),
[profile],
)
projection = replay_ledger(ledger, [profile])
signal_id = projection["reopen_condition_signals"][0]["event_id"]
rendered = checkpoint_summary(
projection,
moment="reopen_condition_signal",
signal_event_id=signal_id,
env={ENV_FLAG: "1"},
)
assert (
"main [parked; author_originated] — AUTHOR JUDGMENT REQUIRED" in rendered
)
assert "result-row-7" in rendered
with pytest.raises(ContractError, match="required"):
checkpoint_summary(
projection,
moment="reopen_condition_signal",
env={ENV_FLAG: "1"},
)
def test_signal_summary_rejects_retired_condition_or_nonreopenable_branch() -> None:
ledger, profile = _two_branch_ledger()
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "await evidence"}, minute=2),
[profile],
)
signaled = append_event(
ledger,
_event(
"reopen_condition_signal",
"main",
{
"branch_id_ref": "main",
"condition_id": "invariance-fails",
"evidence_pointer": "result-row-7",
},
actor="ai",
minute=3,
),
[profile],
)
signal_id = replay_ledger(signaled, [profile])["reopen_condition_signals"][0][
"event_id"
]
retired = append_event(
signaled,
_event(
"branch_annotated",
"main",
{"field": "reopen_conditions", "value": []},
minute=4,
),
[profile],
)
with pytest.raises(ContractError, match="condition_id is no longer current"):
checkpoint_summary(
replay_ledger(retired, [profile]),
moment="reopen_condition_signal",
signal_event_id=signal_id,
env={ENV_FLAG: "1"},
)
archived = append_event(
signaled,
_event("branch_archived", "main", {"reason": "closed"}, minute=4),
[profile],
)
with pytest.raises(ContractError, match="not currently eligible"):
checkpoint_summary(
replay_ledger(archived, [profile]),
moment="reopen_condition_signal",
signal_event_id=signal_id,
env={ENV_FLAG: "1"},
)
def test_signal_summary_rejects_active_or_unadopted_ai_branch() -> None:
ledger, profile = _two_branch_ledger()
active_signal = append_event(
ledger,
_event(
"reopen_condition_signal",
"main",
{
"branch_id_ref": "main",
"condition_id": "invariance-fails",
"evidence_pointer": "result-row-7",
},
actor="ai",
minute=2,
),
[profile],
)
projection = replay_ledger(active_signal, [profile])
with pytest.raises(ContractError, match="not currently eligible"):
checkpoint_summary(
projection,
moment="reopen_condition_signal",
signal_event_id=projection["reopen_condition_signals"][0]["event_id"],
env={ENV_FLAG: "1"},
)
annotated = append_event(
ledger,
_event(
"branch_annotated",
"facet",
{
"field": "reopen_conditions",
"value": [
{"condition_id": "facet-signal", "statement": "Facet condition"}
],
},
minute=2,
),
[profile],
)
facet_signal = append_event(
annotated,
_event(
"reopen_condition_signal",
"facet",
{
"branch_id_ref": "facet",
"condition_id": "facet-signal",
"evidence_pointer": "result-row-9",
},
actor="ai",
minute=3,
),
[profile],
)
projection = replay_ledger(facet_signal, [profile])
with pytest.raises(ContractError, match="not currently eligible"):
checkpoint_summary(
projection,
moment="reopen_condition_signal",
signal_event_id=projection["reopen_condition_signals"][0]["event_id"],
env={ENV_FLAG: "1"},
)
def test_absent_and_orphan_pointer_states(tmp_path: Path) -> None:
profile = _profile()
passport = _passport(tmp_path / "passport.yaml")
absent = load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
assert absent["state"] == "absent"
assert (tmp_path / ".passport.yaml.lock").is_file()
assert not (tmp_path / ".passport.yaml.inquiry-ledger.lock").exists()
default_relative = default_ledger_relative_path(passport, tmp_path)
(tmp_path / default_relative).write_text("not even json", encoding="utf-8")
orphan = load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
assert orphan["state"] == "orphan_ignored"
assert "passport is authoritative" in orphan["notice"]
def test_shared_passport_sidecar_excludes_another_current_writer(
tmp_path: Path,
) -> None:
if file_lock.BACKEND != "fcntl":
pytest.skip("POSIX advisory locking is unavailable")
profile = _profile()
passport = _passport(tmp_path / "passport.yaml")
lock_path = tmp_path / ".passport.yaml.lock"
lock_path.touch(mode=0o600)
with lock_path.open("r+") as held:
file_lock.acquire(held.fileno(), exclusive=True, timeout=0)
with pytest.raises(ContractError, match="passport locked by another session"):
load_bound_ledger(
passport,
tmp_path,
[profile],
expected_project_ref="project-alpha",
lock_timeout=0,
)
@pytest.mark.parametrize("lock_timeout", [float("nan"), float("inf"), float("-inf")])
def test_authoritative_lock_timeout_must_be_finite(
tmp_path: Path, lock_timeout: float
) -> None:
profile = _profile()
passport = _passport(tmp_path / "passport.yaml")
with pytest.raises(ContractError, match="finite number between 0 and 60"):
load_bound_ledger(
passport,
tmp_path,
[profile],
expected_project_ref="project-alpha",
lock_timeout=lock_timeout,
)
assert not (tmp_path / ".passport.yaml.lock").exists()
def test_authoritative_calls_require_project_identity_and_reject_null_pointer(
tmp_path: Path,
) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
with pytest.raises(ContractError, match="expected_project_ref"):
load_bound_ledger(passport, tmp_path, [profile])
with pytest.raises(ContractError, match="expected_project_ref"):
commit_ledger_transaction(
passport,
"passport.inquiry-branch-ledger.json",
tmp_path,
ledger,
[profile],
)
passport.write_text(
passport.read_text(encoding="utf-8") + "inquiry_ledger_ref: null\n",
encoding="utf-8",
)
with pytest.raises(LedgerBindingError, match="present but null"):
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
with pytest.raises(LedgerBindingError, match="present but null"):
commit_ledger_transaction(
passport,
"passport.inquiry-branch-ledger.json",
tmp_path,
ledger,
[profile],
"project-alpha",
)
@pytest.mark.parametrize(
"reserved_name",
[
".passport.yaml.lock",
".passport.yaml.inquiry-ledger.transaction.json",
".passport.yaml.inquiry-ledger.transaction.tmp",
".passport.yaml.inquiry-ledger.passport.tmp",
".passport.yaml.inquiry-ledger.ledger.tmp",
".passport.yaml.inquiry-ledger.register.tmp",
".PASSPORT.YAML.INQUIRY-LEDGER.LEDGER.TMP",
".PASSPORT.YAML.INQUIRY-LEDGER.REGISTER.TMP",
],
)
def test_commit_rejects_every_reserved_passport_transaction_target(
tmp_path: Path, reserved_name: str
) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
with pytest.raises(ContractError, match="reserved passport transaction"):
commit_ledger_transaction(
passport,
reserved_name,
tmp_path,
ledger,
[profile],
"project-alpha",
)
def test_commit_rejects_casefolded_passport_target_alias(tmp_path: Path) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
with pytest.raises(ContractError, match="must not equal passport_path"):
commit_ledger_transaction(
passport,
"PASSPORT.YAML",
tmp_path,
ledger,
[profile],
"project-alpha",
)
@pytest.mark.parametrize("absolute", [False, True])
def test_commit_rejects_relative_and_absolute_symlink_ledger_targets(
tmp_path: Path, absolute: bool
) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
target = tmp_path / "actual-ledger.json"
alias = tmp_path / "ledger-alias.json"
alias.symlink_to(target.name)
ledger_argument = alias if absolute else alias.name
with pytest.raises(ContractError, match="regular non-symlink"):
commit_ledger_transaction(
passport,
ledger_argument,
tmp_path,
ledger,
[profile],
"project-alpha",
)
assert alias.is_symlink()
assert not target.exists()
@pytest.mark.parametrize("operation", ["commit", "load", "recover"])
def test_authoritative_operations_reject_symlinked_passport_parent(
tmp_path: Path, operation: str
) -> None:
ledger, profile = _two_branch_ledger()
actual = tmp_path / "actual"
actual.mkdir()
passport = _passport(actual / "passport.yaml")
alias = tmp_path / "alias"
alias.symlink_to(actual, target_is_directory=True)
alias_passport = alias / passport.name
with pytest.raises(ContractError, match="parent directory.*symlink"):
if operation == "commit":
commit_ledger_transaction(
alias_passport,
actual / "passport.inquiry-branch-ledger.json",
tmp_path,
ledger,
[profile],
"project-alpha",
)
elif operation == "load":
load_bound_ledger(
alias_passport,
tmp_path,
[profile],
expected_project_ref="project-alpha",
)
else:
recover_ledger_transaction(alias_passport, tmp_path)
def test_commit_and_bound_load_preserve_passport_comment_and_mode(tmp_path: Path) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
os.chmod(passport, 0o640)
pointer = commit_ledger_transaction(
passport,
"passport.inquiry-branch-ledger.json",
tmp_path,
ledger,
[profile],
"project-alpha",
)
assert pointer["content_sha256"] == hashlib.sha256(canonical_bytes(ledger)).hexdigest()
assert "# keep this comment" in passport.read_text(encoding="utf-8")
assert stat.S_IMODE(passport.stat().st_mode) == 0o640
loaded = load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
assert loaded["state"] == "bound"
assert loaded["ledger"] == ledger
assert loaded["projection"]["introduced_branch_count"] == 2
def test_binding_breaks_on_missing_mismatch_noncanonical_and_project_drift(
tmp_path: Path,
) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
ledger_path = tmp_path / "passport.inquiry-branch-ledger.json"
commit_ledger_transaction(
passport, ledger_path, tmp_path, ledger, [profile], "project-alpha"
)
raw = ledger_path.read_bytes()
ledger_path.unlink()
with pytest.raises(LedgerBindingError, match="LEDGER-BINDING-BROKEN"):
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
ledger_path.write_bytes(raw + b"\n")
with pytest.raises(LedgerBindingError, match="exact canonical"):
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
ledger_path.write_bytes(raw)
with pytest.raises(LedgerBindingError, match="expected project_ref"):
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="another-project"
)
ledger_path.write_bytes(raw[:-1] + (b"0" if raw[-1:] != b"0" else b"1"))
with pytest.raises(LedgerBindingError):
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
def test_passport_digest_detects_valid_prefix_truncation(tmp_path: Path) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
relative = "passport.inquiry-branch-ledger.json"
commit_ledger_transaction(
passport, relative, tmp_path, ledger, [profile], "project-alpha"
)
truncated = copy.deepcopy(ledger)
truncated["events"] = truncated["events"][:1]
(tmp_path / relative).write_bytes(canonical_bytes(truncated))
with pytest.raises(LedgerBindingError, match="pointer digest"):
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
@pytest.mark.parametrize(
"crash_phase",
["journal_durable", "ledger_published", "passport_published"],
)
def test_transaction_recovers_every_post_journal_crash(
tmp_path: Path, crash_phase: str
) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
relative = "passport.inquiry-branch-ledger.json"
commit_ledger_transaction(
passport, relative, tmp_path, ledger, [profile], "project-alpha"
)
updated = _adopt_facet(ledger, [profile])
def crash(phase: str) -> None:
if phase == crash_phase:
raise RuntimeError(f"crash at {phase}")
with pytest.raises(RuntimeError, match="crash at"):
commit_ledger_transaction(
passport,
relative,
tmp_path,
updated,
[profile],
"project-alpha",
crash_hook=crash,
)
assert recover_ledger_transaction(passport, tmp_path) is True
loaded = load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
assert loaded["ledger"] == updated
assert loaded["projection"]["event_count"] == 3
assert recover_ledger_transaction(passport, tmp_path) is False
def test_journal_binds_complete_old_and_new_passport_generations(
tmp_path: Path,
) -> None:
passport, ledger_path, journal_path, updated, profile = _leave_update_journal(
tmp_path
)
journal = json.loads(journal_path.read_text(encoding="utf-8"))
passport_temp = tmp_path / journal["passport_temp_path"]
ledger_temp = tmp_path / journal["ledger_temp_path"]
assert journal["old_passport_sha256"] == hashlib.sha256(
passport.read_bytes()
).hexdigest()
assert journal["new_passport_sha256"] == hashlib.sha256(
passport_temp.read_bytes()
).hexdigest()
assert journal["old_ledger_sha256"] == journal["old_pointer"]["content_sha256"]
assert journal["new_ledger_sha256"] == journal["new_pointer"]["content_sha256"]
assert journal["new_pointer"]["ledger_path"] == journal["ledger_path"]
assert hashlib.sha256(ledger_temp.read_bytes()).hexdigest() == journal[
"new_ledger_sha256"
]
assert recover_ledger_transaction(passport, tmp_path) is True
loaded = load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
assert Path(loaded["ledger_path"]) == ledger_path
assert loaded["ledger"] == updated
@pytest.mark.parametrize(
"mutation",
[
"new_pointer_path",
"old_pointer_digest",
"passport_temp_path",
"ledger_temp_path",
"reserved_lock_target",
"reserved_journal_target",
"reserved_journal_temp_target",
"reserved_passport_temp_target",
"reserved_ledger_temp_target",
"reserved_register_temp_target",
"casefold_reserved_ledger_temp_target",
"casefold_reserved_register_temp_target",
],
)
def test_recovery_rejects_mutated_journal_relations_before_publication(
tmp_path: Path, mutation: str
) -> None:
passport, ledger_path, journal_path, _, _ = _leave_update_journal(tmp_path)
old_passport = passport.read_bytes()
old_ledger = ledger_path.read_bytes()
journal = json.loads(journal_path.read_text(encoding="utf-8"))
if mutation == "new_pointer_path":
journal["new_pointer"]["ledger_path"] = "unbound.json"
elif mutation == "old_pointer_digest":
journal["old_ledger_sha256"] = "f" * 64
elif mutation == "passport_temp_path":
journal["passport_temp_path"] = "unrelated-passport.yaml"
elif mutation == "ledger_temp_path":
journal["ledger_temp_path"] = "unrelated-ledger.json"
else:
reserved = {
"reserved_lock_target": ".passport.yaml.lock",
"reserved_journal_target": (
".passport.yaml.inquiry-ledger.transaction.json"
),
"reserved_journal_temp_target": (
".passport.yaml.inquiry-ledger.transaction.tmp"
),
"reserved_passport_temp_target": (
".passport.yaml.inquiry-ledger.passport.tmp"
),
"reserved_ledger_temp_target": (
".passport.yaml.inquiry-ledger.ledger.tmp"
),
"reserved_register_temp_target": (
".passport.yaml.inquiry-ledger.register.tmp"
),
"casefold_reserved_ledger_temp_target": (
".PASSPORT.YAML.INQUIRY-LEDGER.LEDGER.TMP"
),
"casefold_reserved_register_temp_target": (
".PASSPORT.YAML.INQUIRY-LEDGER.REGISTER.TMP"
),
}[mutation]
journal["ledger_path"] = reserved
journal["old_pointer"]["ledger_path"] = reserved
journal["new_pointer"]["ledger_path"] = reserved
journal_path.write_bytes(canonical_bytes(journal))
with pytest.raises(TransactionRecoveryError, match="RECOVERY-REQUIRED"):
recover_ledger_transaction(passport, tmp_path)
assert passport.read_bytes() == old_passport
assert ledger_path.read_bytes() == old_ledger
assert journal_path.is_file()
def test_recovery_validates_complete_staged_passport_before_either_replace(
tmp_path: Path,
) -> None:
passport, ledger_path, journal_path, _, _ = _leave_update_journal(tmp_path)
old_passport = passport.read_bytes()
old_ledger = ledger_path.read_bytes()
journal = json.loads(journal_path.read_text(encoding="utf-8"))
passport_temp = tmp_path / journal["passport_temp_path"]
passport_temp.write_bytes(passport_temp.read_bytes() + b"# external mutation\n")
with pytest.raises(TransactionRecoveryError, match="complete new byte image"):
recover_ledger_transaction(passport, tmp_path)
assert passport.read_bytes() == old_passport
assert ledger_path.read_bytes() == old_ledger
@pytest.mark.parametrize("temp_field", ["ledger_temp_path", "passport_temp_path"])
def test_recovery_rejects_symlinked_staged_sources_before_digest_or_replace(
tmp_path: Path, temp_field: str
) -> None:
passport, ledger_path, journal_path, _, _ = _leave_update_journal(tmp_path)
old_passport = passport.read_bytes()
old_ledger = ledger_path.read_bytes()
journal = json.loads(journal_path.read_text(encoding="utf-8"))
staged = tmp_path / journal[temp_field]
staged_copy = tmp_path / f"copy-{temp_field}"
staged_copy.write_bytes(staged.read_bytes())
staged.unlink()
staged.symlink_to(staged_copy)
with pytest.raises(TransactionRecoveryError, match="non-symlink"):
recover_ledger_transaction(passport, tmp_path)
assert passport.read_bytes() == old_passport
assert ledger_path.read_bytes() == old_ledger
def test_live_passport_full_byte_cas_preserves_concurrent_edit(tmp_path: Path) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
ledger_path = tmp_path / "passport.inquiry-branch-ledger.json"
commit_ledger_transaction(
passport, ledger_path, tmp_path, ledger, [profile], "project-alpha"
)
old_ledger = ledger_path.read_bytes()
updated = _adopt_facet(ledger, [profile])
def mutate_without_crashing(phase: str) -> None:
if phase == "journal_durable":
passport.write_text(
passport.read_text(encoding="utf-8") + "external_note: keep-me\n",
encoding="utf-8",
)
with pytest.raises(TransactionRecoveryError, match="live passport changed"):
commit_ledger_transaction(
passport,
ledger_path,
tmp_path,
updated,
[profile],
"project-alpha",
crash_hook=mutate_without_crashing,
)
assert "external_note: keep-me" in passport.read_text(encoding="utf-8")
assert ledger_path.read_bytes() == old_ledger
with pytest.raises(TransactionRecoveryError, match="neither the recorded old nor new"):
recover_ledger_transaction(passport, tmp_path)
def test_live_ledger_full_byte_cas_preserves_concurrent_edit(tmp_path: Path) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
ledger_path = tmp_path / "passport.inquiry-branch-ledger.json"
commit_ledger_transaction(
passport, ledger_path, tmp_path, ledger, [profile], "project-alpha"
)
old_passport = passport.read_bytes()
updated = _adopt_facet(ledger, [profile])
def mutate_without_crashing(phase: str) -> None:
if phase == "journal_durable":
ledger_path.write_bytes(ledger_path.read_bytes() + b"\n")
with pytest.raises(TransactionRecoveryError, match="live ledger changed"):
commit_ledger_transaction(
passport,
ledger_path,
tmp_path,
updated,
[profile],
"project-alpha",
crash_hook=mutate_without_crashing,
)
assert passport.read_bytes() == old_passport
assert ledger_path.read_bytes().endswith(b"\n")
with pytest.raises(TransactionRecoveryError, match="neither the recorded old nor new"):
recover_ledger_transaction(passport, tmp_path)
def test_prejournal_crash_keeps_old_pair_and_retry_cleans_temps(tmp_path: Path) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
relative = "passport.inquiry-branch-ledger.json"
commit_ledger_transaction(
passport, relative, tmp_path, ledger, [profile], "project-alpha"
)
updated = _adopt_facet(ledger, [profile])
def crash(phase: str) -> None:
if phase == "temps_durable":
raise RuntimeError("prejournal")
with pytest.raises(RuntimeError, match="prejournal"):
commit_ledger_transaction(
passport,
relative,
tmp_path,
updated,
[profile],
"project-alpha",
crash_hook=crash,
)
assert recover_ledger_transaction(passport, tmp_path) is False
assert (
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)["ledger"]
== ledger
)
commit_ledger_transaction(
passport, relative, tmp_path, updated, [profile], "project-alpha"
)
assert (
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)["ledger"]
== updated
)
def test_crash_after_journal_clear_is_already_committed(tmp_path: Path) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
relative = "passport.inquiry-branch-ledger.json"
def crash(phase: str) -> None:
if phase == "journal_cleared":
raise RuntimeError("after commit")
with pytest.raises(RuntimeError, match="after commit"):
commit_ledger_transaction(
passport,
relative,
tmp_path,
ledger,
[profile],
"project-alpha",
crash_hook=crash,
)
assert recover_ledger_transaction(passport, tmp_path) is False
assert (
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)["ledger"]
== ledger
)
def test_corrupt_recovery_journal_fails_visible(tmp_path: Path) -> None:
profile = _profile()
passport = _passport(tmp_path / "passport.yaml")
journal = tmp_path / ".passport.yaml.inquiry-ledger.transaction.json"
journal.write_text("{broken", encoding="utf-8")
with pytest.raises(TransactionRecoveryError, match="RECOVERY-REQUIRED"):
load_bound_ledger(
passport, tmp_path, [profile], expected_project_ref="project-alpha"
)
def test_transaction_refuses_rewrite_noop_path_switch_and_orphan_adoption(
tmp_path: Path,
) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
relative = "passport.inquiry-branch-ledger.json"
commit_ledger_transaction(
passport, relative, tmp_path, ledger, [profile], "project-alpha"
)
with pytest.raises(ContractError, match="append at least one"):
commit_ledger_transaction(
passport, relative, tmp_path, ledger, [profile], "project-alpha"
)
rewritten = _adopt_facet(ledger, [profile])
rewritten["events"][0]["payload"]["statement"] = "history rewrite"
# Repair the chain to prove append-only prefix comparison, not hash checking,
# is what catches a fully rehashed historical rewrite.
for index, event in enumerate(rewritten["events"]):
event["prev_event_sha256"] = (
"0" * 64
if index == 0
else hashlib.sha256(canonical_bytes(rewritten["events"][index - 1])).hexdigest()
)
with pytest.raises((ContractError, LedgerBindingError), match="rewritten|reordered"):
commit_ledger_transaction(
passport, relative, tmp_path, rewritten, [profile], "project-alpha"
)
with pytest.raises(ContractError, match="stable ledger_path"):
commit_ledger_transaction(
passport,
"other.inquiry-branch-ledger.json",
tmp_path,
_adopt_facet(ledger, [profile]),
[profile],
"project-alpha",
)
orphan_passport = _passport(tmp_path / "other-passport.yaml")
orphan_relative = "other-passport.inquiry-branch-ledger.json"
(tmp_path / orphan_relative).write_bytes(canonical_bytes(ledger))
with pytest.raises(ContractError, match="ignored orphan"):
commit_ledger_transaction(
orphan_passport,
orphan_relative,
tmp_path,
ledger,
[profile],
"project-alpha",
)
def test_publication_refuses_simple_path_and_workspace_escape(tmp_path: Path) -> None:
profile = _profile()
passport = _passport(tmp_path / "passport.yaml")
one = new_ledger("project-alpha", profile)
one = append_event(
one,
_event("branch_created", "main", _created_payload("Main")),
[profile],
)
with pytest.raises(ContractError, match="at least two"):
commit_ledger_transaction(
passport,
"passport.inquiry-branch-ledger.json",
tmp_path,
one,
[profile],
"project-alpha",
)
with pytest.raises(ContractError, match=r"\.\.|workspace-relative"):
commit_ledger_transaction(
passport,
"../escape.json",
tmp_path,
_two_branch_ledger(profile)[0],
[profile],
"project-alpha",
)
def test_cli_validate_replay_append_and_default_off_summary(tmp_path: Path) -> None:
ledger, profile = _two_branch_ledger()
ledger_path = _write_canonical(tmp_path / "ledger.json", ledger)
profile_path = _write_canonical(tmp_path / "profile.json", profile)
validate = subprocess.run(
[
sys.executable,
str(RUNTIME),
"validate",
str(ledger_path),
"--profile",
str(profile_path),
"--project-ref",
"project-alpha",
],
cwd=REPO_ROOT,
capture_output=True,
text=True,
)
assert validate.returncode == 0, validate.stderr
assert json.loads(validate.stdout)["status"] == "valid"
replay = subprocess.run(
[
sys.executable,
str(RUNTIME),
"replay",
str(ledger_path),
"--profile",
str(profile_path),
],
cwd=REPO_ROOT,
capture_output=True,
text=True,
)
assert replay.returncode == 0, replay.stderr
assert json.loads(replay.stdout)["introduced_branch_count"] == 2
event_path = _write_canonical(
tmp_path / "event.json",
_event(
"branch_adopted",
"facet",
{
"source_event_id": 2,
"surfaced_text": "Alternative mechanism",
"author_formulation": "Author-owned alternative mechanism",
},
minute=2,
),
)
appended = subprocess.run(
[
sys.executable,
str(RUNTIME),
"append",
str(ledger_path),
"--profile",
str(profile_path),
"--project-ref",
"project-alpha",
"--event",
str(event_path),
],
cwd=REPO_ROOT,
capture_output=True,
text=True,
)
assert appended.returncode == 0, appended.stderr
assert len(json.loads(appended.stdout)["events"]) == 3
env = dict(os.environ)
env.pop(ENV_FLAG, None)
summary = subprocess.run(
[
sys.executable,
str(RUNTIME),
"summary",
str(ledger_path),
"--profile",
str(profile_path),
"--project-ref",
"project-alpha",
"--moment",
"stage_2_5",
],
cwd=REPO_ROOT,
env=env,
capture_output=True,
text=True,
)
assert summary.returncode == 0, summary.stderr
assert summary.stdout == ""
forced = subprocess.run(
[*summary.args, "--force"],
cwd=REPO_ROOT,
env=env,
capture_output=True,
text=True,
)
assert forced.returncode == 0, forced.stderr
assert "Inquiry branches" in forced.stdout
@pytest.mark.parametrize("command", ["append", "summary", "load-bound", "commit"])
def test_authoritative_cli_commands_require_project_ref(
tmp_path: Path, command: str
) -> None:
ledger, profile = _two_branch_ledger()
passport = _passport(tmp_path / "passport.yaml")
ledger_path = _write_canonical(tmp_path / "ledger-input.json", ledger)
profile_path = _write_canonical(tmp_path / "profile.json", profile)
if command in {"append", "summary"}:
args = [
sys.executable,
str(RUNTIME),
command,
str(ledger_path),
"--profile",
str(profile_path),
]
if command == "append":
event_path = _write_canonical(
tmp_path / "event.json",
_event(
"branch_adopted",
"facet",
{
"source_event_id": 2,
"surfaced_text": "Alternative mechanism",
"author_formulation": "Author-owned alternative mechanism",
},
minute=2,
),
)
args.extend(["--event", str(event_path)])
else:
args.extend(["--moment", "stage_2_5"])
else:
args = [
sys.executable,
str(RUNTIME),
command,
"--passport",
str(passport),
"--workspace-root",
str(tmp_path),
"--profile",
str(profile_path),
]
if command == "commit":
args.extend(
[
"--ledger-path",
"passport.inquiry-branch-ledger.json",
"--ledger",
str(ledger_path),
]
)
result = subprocess.run(
args,
cwd=REPO_ROOT,
capture_output=True,
text=True,
)
assert result.returncode == 2
assert "--project-ref" in result.stderr and "required" in result.stderr
def test_render_summary_excludes_archived_and_merged_details() -> None:
ledger, profile = _two_branch_ledger()
ledger = _adopt_facet(ledger, [profile])
ledger = append_event(
ledger,
_event(
"branch_merged",
"facet",
{"merged_into": "main", "reason": "combined"},
minute=3,
),
[profile],
)
text = render_summary(replay_ledger(ledger, [profile]))
assert "main [active; author_originated]" in text
assert "facet [" not in text
assert "merged=" not in text
def test_render_summary_lists_every_stale_artifact_and_cause() -> None:
ledger, profile = _two_branch_ledger()
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "wait"}, minute=2),
[profile],
)
ledger = append_event(
ledger,
_event("branch_reopened", "main", {"reason": "new result"}, minute=3),
[profile],
)
ledger = append_event(
ledger,
_event("branch_parked", "main", {"reason": "wait again"}, minute=4),
[profile],
)
ledger = append_event(
ledger,
_event("branch_reopened", "main", {"reason": "second result"}, minute=5),
[profile],
)
rendered = render_summary(replay_ledger(ledger, [profile]))
assert "Stale artifacts (2)" in rendered
assert "draft-v1 [outstanding=2]" in rendered
assert "shared-table [outstanding=2]" in rendered
for cause_id in (5, 6, 9, 10):
assert f"cause_event_id={cause_id}" in rendered
def test_render_summary_bounds_and_escapes_untrusted_display_text() -> None:
projection = {
"live_count": 1,
"branch_budget": 3,
"branches": [
{
"branch_id": "main",
"status": "active",
"provenance": "author_originated",
"statement": (
"Primary framing\n- forged [active; author_originated]\n"
"Controls: off" + "\u202e" * 400
),
"reopen_conditions": [],
},
{
"branch_id": "signal-branch",
"status": "parked",
"provenance": "author_adopted",
"statement": "Author-owned signal branch",
"reopen_conditions": [
{
"condition_id": "cond-[forged]",
"statement": "Check `result`\nControls: forged",
}
],
},
],
"reopen_condition_signals": [
{
"event_id": 7,
"branch_id": "signal-branch",
"condition_id": "cond-[forged]",
"condition_statement": "Check `result`\nControls: forged",
"evidence_pointer": "row\n- fake status",
}
],
"artifacts": [
{
"artifact_ref": f"artifact-{index}\nControls: forged",
"stale": True,
"outstanding_stale_causes": [index + 10],
}
for index in range(6)
],
}
rendered = render_summary(projection, signal_event_id=7)
lines = rendered.splitlines()
assert len(lines) == 18
assert rendered.count("Controls: skip | off | reset-to-simple-path") == 1
assert "\n- forged" not in rendered
assert "\\[active; author\\_originated\\]" in rendered
assert (
"signal-branch [parked; author_adopted] — AUTHOR JUDGMENT REQUIRED"
in rendered
)
assert "\\u202e" in rendered
assert "" in rendered
assert "Stale artifacts (6)" in rendered
assert "+1 more" not in rendered
for index in range(6):
assert f"artifact-{index} Controls: forged" in rendered
assert f"cause_event_id={index + 10}" in rendered
assert all(len(line) <= 300 for line in lines)
def test_pipeline_prompt_integration_pins_all_three_summary_owners() -> None:
skill = (REPO_ROOT / "academic-pipeline" / "SKILL.md").read_text(
encoding="utf-8"
)
orchestrator = (
REPO_ROOT
/ "academic-pipeline"
/ "agents"
/ "pipeline_orchestrator_agent.md"
).read_text(encoding="utf-8")
architect = (
REPO_ROOT
/ "deep-research"
/ "agents"
/ "research_architect_agent.md"
).read_text(encoding="utf-8")
reset_protocol = (
REPO_ROOT
/ "academic-pipeline"
/ "references"
/ "passport_as_reset_boundary.md"
).read_text(encoding="utf-8")
for surface in (skill, orchestrator):
assert "ARS_INQUIRY_LEDGER=1" in surface
assert "scripts/inquiry_branch_ledger.py" in surface
assert "Stage 1 design-freeze" in surface
assert "Stage 2.5" in surface and "Stage 4.5" in surface
assert "reset-to-simple-path" in surface
assert "scripts/inquiry_branch_ledger.py::checkpoint_summary" in architect
assert "moment=design_freeze" in architect
assert (
"omit the entire heading and ask no additional branch question"
in " ".join(architect.split())
)
for surface in (orchestrator, reset_protocol):
assert ".<passport-basename>.lock" in surface
assert "replaceable passport inode" in surface