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
5 changes: 5 additions & 0 deletions polylogue/storage/raw_retention.py
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,11 @@ def raw_frontier_blocked_source_paths(
) -> RawFrontierBlockedPaths:
"""Attribute the frontier proof's refusals to exact source paths."""

if not (archive_root / "source.db").is_file():
# No source tier means nothing has been acquired yet, so there is
# nothing to select and nothing to refuse. An unreadable tier still
# refuses below: absence and damage are different states.
return RawFrontierBlockedPaths(frozenset(), None)
projection = raw_frontier_integrity_projection(
archive_root,
raw_materialization_readiness,
Expand Down
10 changes: 9 additions & 1 deletion tests/unit/maintenance/test_archive_verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -1419,12 +1419,20 @@ def test_blob_refs_liveness_passes_on_coherent_archive(tmp_path: Path) -> None:


def test_blob_reference_closure_rejects_acquired_attachment_without_ref(tmp_path: Path) -> None:
"""An acquired attachment whose refs vanished is archive debt.

``ref_count`` is the discriminator: a non-zero count with no surviving
``attachment_refs`` row means the sweep lost edges it once had, while a
zero count is an attachment that never had one.

Anti-vacuity: seeding ``ref_count`` 0 instead describes the explained
shape and the check stays clean."""
_seed_coherent_archive(tmp_path)
conn = _connect(tmp_path / "index.db")
try:
conn.execute(
"INSERT INTO attachments (attachment_id, byte_count, blob_hash, acquisition_status, ref_count) "
"VALUES ('orphan-acquired', 1, ?, 'acquired', 0)",
"VALUES ('orphan-acquired', 1, ?, 'acquired', 1)",
(b"a" * 32,),
)
conn.commit()
Expand Down
17 changes: 17 additions & 0 deletions tests/unit/storage/test_raw_retention.py
Original file line number Diff line number Diff line change
Expand Up @@ -2577,6 +2577,23 @@ def test_deferred_cursor_never_blocks_source_selection(tmp_path: Path) -> None:
assert raw_frontier_source_selection_block_reason(tmp_path) is None


def test_absent_source_tier_refuses_nothing(tmp_path: Path) -> None:
"""An archive root with no source tier has nothing to select or refuse.

Anti-vacuity: dropping the absence branch makes the projection report
the tier unavailable under both the broken-head and cursor checks, and
those reasons surface as an unattributed refusal that blocks the whole
materialization pass on a freshly created archive.
"""
archive_root = tmp_path / "archive"
archive_root.mkdir()

blocked = raw_retention_mod.raw_frontier_blocked_source_paths(archive_root, {})

assert blocked.unattributed_reason is None
assert blocked.source_paths == frozenset()


def test_blocked_source_paths_refuse_violations_and_admit_authority_gaps(tmp_path: Path) -> None:
"""A violation names the path it refuses; a gap names a path only processing can resolve.

Expand Down