mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 16:53:38 +00:00
Agent-Logs-Url: https://github.com/velocitatem/cvfs/sessions/e5483685-0807-4655-ba29-68311e6403db Co-authored-by: velocitatem <60182044+velocitatem@users.noreply.github.com>
40 lines
1.3 KiB
Python
40 lines
1.3 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Iterable
|
|
|
|
from .schema import PatchPayload, PatchOperation, StructuredDocument
|
|
|
|
|
|
class PatchValidationError(ValueError):
|
|
pass
|
|
|
|
|
|
def validate_patchset(
|
|
document: StructuredDocument,
|
|
patches: Iterable[PatchPayload],
|
|
*,
|
|
max_growth_ratio: float = 1.45,
|
|
) -> None:
|
|
patch_list = list(patches)
|
|
block_map = {block.path: block for block in document.blocks}
|
|
for patch in patch_list:
|
|
block = block_map.get(patch.target_path)
|
|
if not block:
|
|
raise PatchValidationError(
|
|
f"Target path {patch.target_path} does not exist in base document"
|
|
)
|
|
if patch.operation == PatchOperation.REPLACE_TEXT:
|
|
if not patch.new_value:
|
|
raise PatchValidationError("replace_text requires new_value")
|
|
baseline = len(block.text.strip()) or 1
|
|
if len(patch.new_value.strip()) / baseline > max_growth_ratio:
|
|
raise PatchValidationError("Patch grows text beyond ATS safe threshold")
|
|
if (
|
|
patch.operation
|
|
in {PatchOperation.REMOVE_BLOCK, PatchOperation.SUPPRESS_BLOCK}
|
|
and block.block_type == "heading"
|
|
):
|
|
raise PatchValidationError(
|
|
"Headings cannot be removed without manual confirmation"
|
|
)
|