{"record":{"id":"d22a93241f080cad","repo":"HKUDS/Vibe-Trading","slug":"result-first-break","errorCode":null,"errorMessage":"{result.first_break}","messagePattern":"\\{result\\.first_break\\}","errorType":"error_code","errorClass":"LedgerCorruptionError","httpStatus":null,"severity":"critical","filePath":"agent/src/governance/ledger.py","lineNumber":655,"sourceCode":"        max_bytes: Size at or above which the active file is sealed.\n        fsync: Whether to fsync the directory after the rename.\n\n    Returns:\n        The archive path when a rotation happened, else None.\n\n    Raises:\n        ValueError: If ``max_bytes`` is not positive.\n        LedgerCorruptionError: If the active chain is broken -- a corrupt\n            ledger is sealed by nobody; fix or quarantine it deliberately.\n    \"\"\"\n    if max_bytes <= 0:\n        raise ValueError(f\"max_bytes must be positive, got {max_bytes}\")\n    if not path.exists() or path.stat().st_size < max_bytes:\n        return None\n\n    result = verify_chain(path)\n    if not result.ok:\n        raise LedgerCorruptionError(result.first_break)\n\n    counter = len(archive_segments(path)) + 1\n    archive = path.with_name(f\"{path.stem}.{counter:0{ARCHIVE_SUFFIX_WIDTH}d}{path.suffix}\")\n    path.rename(archive)\n    if fsync:\n        _fsync_dir(path.parent)\n    return archive\n\n\ndef verify_chain_with_archives(path: Path) -> ChainVerificationResult:\n    \"\"\"Verify a ledger's whole history, sealed segments included.\n\n    Walks the archives oldest-first and then the active file, checking that each\n    segment's first record continues from the previous segment's last\n    ``record_hash``. A segment deleted wholesale therefore shows up as a break\n    at the seam, which is exactly what plain per-file verification would miss.\n\n    Args:","sourceCodeStart":637,"sourceCodeEnd":673,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/governance/ledger.py#L637-L673","documentation":"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.","triggerScenarios":"The active ledger file already exceeds max_bytes AND its chain is broken (edited/deleted record), and rotate_if_needed is called.","commonSituations":"Corruption went unnoticed during appends (fsync disabled) and surfaces at rotation; disk-level damage; manual edits between rotations.","solutions":["Verify with verify_chain(path) in monitoring so corruption is caught before rotation time","Quarantine the corrupt active file deliberately, then let rotation start a fresh segment","Never delete/rename the corrupt file without preserving it — forensic value"],"exampleFix":"# before\nrotate_if_needed(path, max_bytes=MAX)  # raises on corrupt active file\n# after\nresult = verify_chain(path)\nif not result.ok:\n    shutil.move(path, quarantine / path.name)\nrotate_if_needed(path, max_bytes=MAX)","handlingStrategy":"fallback","validationCode":"result = verify_chain(path)\nif not result.ok:\n    quarantine(path)  # deliberate handling instead of blind rotation","typeGuard":"def safe_to_rotate(path) -> bool:\n    return verify_chain(path).ok","tryCatchPattern":"except LedgerCorruptionError as e: quarantine the active file preserving evidence, then rotate/restart with a clean segment","preventionTips":["Monitor chain health so corruption never first surfaces at rotation","Never seal or delete a file that failed verification","Keep sealed segments and active file under the same integrity checks"],"tags":["ledger","rotation","tamper-detection","corruption","python"],"backgroundTag":"audit-log-tamper-detected","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}