HKUDS/Vibe-Trading · critical · LedgerCorruptionError

{result.first_break}

Error message

{result.first_break}

What it means

rotate_if_needed seals segments only if the active chain verifies; a corrupt ledger raises LedgerCorruptionError carrying the first break description rather than archiving tampered history under a sealed name.

Source

Thrown at agent/src/governance/ledger.py:655

        max_bytes: Size at or above which the active file is sealed.
        fsync: Whether to fsync the directory after the rename.

    Returns:
        The archive path when a rotation happened, else None.

    Raises:
        ValueError: If ``max_bytes`` is not positive.
        LedgerCorruptionError: If the active chain is broken -- a corrupt
            ledger is sealed by nobody; fix or quarantine it deliberately.
    """
    if max_bytes <= 0:
        raise ValueError(f"max_bytes must be positive, got {max_bytes}")
    if not path.exists() or path.stat().st_size < max_bytes:
        return None

    result = verify_chain(path)
    if not result.ok:
        raise LedgerCorruptionError(result.first_break)

    counter = len(archive_segments(path)) + 1
    archive = path.with_name(f"{path.stem}.{counter:0{ARCHIVE_SUFFIX_WIDTH}d}{path.suffix}")
    path.rename(archive)
    if fsync:
        _fsync_dir(path.parent)
    return archive


def verify_chain_with_archives(path: Path) -> ChainVerificationResult:
    """Verify a ledger's whole history, sealed segments included.

    Walks the archives oldest-first and then the active file, checking that each
    segment's first record continues from the previous segment's last
    ``record_hash``. A segment deleted wholesale therefore shows up as a break
    at the seam, which is exactly what plain per-file verification would miss.

    Args:

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Verify with verify_chain(path) in monitoring so corruption is caught before rotation time
  2. Quarantine the corrupt active file deliberately, then let rotation start a fresh segment
  3. Never delete/rename the corrupt file without preserving it — forensic value

Example fix

# before
rotate_if_needed(path, max_bytes=MAX)  # raises on corrupt active file
# after
result = verify_chain(path)
if not result.ok:
    shutil.move(path, quarantine / path.name)
rotate_if_needed(path, max_bytes=MAX)
Defensive patterns

Strategy: fallback

Validate before calling

result = verify_chain(path)
if not result.ok:
    quarantine(path)  # deliberate handling instead of blind rotation

Type guard

def safe_to_rotate(path) -> bool:
    return verify_chain(path).ok

Try / catch

except LedgerCorruptionError as e: quarantine the active file preserving evidence, then rotate/restart with a clean segment

Prevention

When it happens

Trigger: The active ledger file already exceeds max_bytes AND its chain is broken (edited/deleted record), and rotate_if_needed is called.

Common situations: Corruption went unnoticed during appends (fsync disabled) and surfaces at rotation; disk-level damage; manual edits between rotations.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/d22a93241f080cad. Report an issue: GitHub.