Initial commit

This commit is contained in:
2026-09-04 14:58:42 +08:00
commit 439cad87d9
4601 changed files with 29440 additions and 0 deletions
+455
View File
@@ -0,0 +1,455 @@
"""Deterministic, source-preserving rewrite planning and application."""
from __future__ import annotations
from collections import defaultdict
from dataclasses import dataclass, replace
import re
from .document import CANONICAL_HEADINGS, HEADING_RE, SkillDocument, section_key
from .models import Annotation, BodyBlock, Operation, Signal
ANNOTATION_SIGNAL = {
"critical_rule": "contextual_rule_adherence",
"definition": "contextual_rule_adherence",
"completion_criterion": "contextual_rule_adherence",
"evidence_priority_rule": "evidence_priority",
"scope_rule": "ambiguity_handling",
"decision_criterion": "ambiguity_handling",
"uncertainty_rule": "uncertainty_calibration",
"viewpoint_side_a": "balanced_presentation",
"viewpoint_side_b": "balanced_presentation",
"coreference": "semantic_robustness",
}
ANNOTATION_TARGET = {
"critical_rule": "critical_rules",
"definition": "definitions",
"completion_criterion": "completion_criterion",
"evidence_priority_rule": "evidence_priority",
"scope_rule": "scope",
"decision_criterion": "decision_criteria",
"uncertainty_rule": "uncertainty_rule",
"viewpoint_side_a": "viewpoint_side_a",
"viewpoint_side_b": "viewpoint_side_b",
}
PRE_SECTION_ORDER = (
"definitions",
"critical_rules",
"evidence_priority",
"scope",
"decision_criteria",
"uncertainty_rule",
"viewpoint_side_a",
"viewpoint_side_b",
)
LOCAL_EMPHASIS_TYPES = {
"critical_rule",
"completion_criterion",
"evidence_priority_rule",
}
PROMINENT_RULE_HEADING_RE = re.compile(
r"\b(?:critical|rules?|constraints?|requirements?|best\s+practices?|"
r"steps?|workflow|procedures?|strategy|priority|verification|validation|"
r"completion)\b|关键|规则|约束|要求|最佳实践|步骤|流程|策略|优先级|验证|完成",
re.I,
)
PROMINENT_RULE_LABEL_RE = re.compile(
r"^(?:(?:[-+*]|\d+[.)])\s+)?"
r"\*\*(?:important|critical|best\s+practice|requirement|rule|"
r"注意|重要|关键|规则|要求)\b",
re.I,
)
class RewriteError(RuntimeError):
"""A deterministic rewrite could not preserve its source span."""
@dataclass(frozen=True)
class _Patch:
start: int
end: int
replacement: str
def _enabled(signal: Signal, annotation: Annotation) -> bool:
return signal.level in {"low", "medium"}
def _heading_text(block: BodyBlock) -> str | None:
match = HEADING_RE.match(block.text)
return match.group(2).strip() if match else None
def _format_payload(quote: str) -> str:
stripped = quote.strip()
ordered = re.match(r"^\d+[.)]\s+(.+)$", stripped, re.S)
if ordered:
return f"- {ordered.group(1).strip()}"
if re.match(r"^[-+*]\s+", stripped):
return stripped
return f"- {stripped}"
def _section_heading(key: str, language: str) -> str:
if key == "viewpoint_side_a":
return "支持方" if language == "zh" else "Supporting View"
if key == "viewpoint_side_b":
return "反对方" if language == "zh" else "Opposing View"
return CANONICAL_HEADINGS[language][key]
def _normalize_known_heading(
block: BodyBlock, language: str
) -> tuple[str | None, Operation | None]:
title = _heading_text(block)
if title is None:
return None, None
key = section_key(title)
if key is None:
return None, None
canonical = CANONICAL_HEADINGS[language][key]
match = HEADING_RE.match(block.text)
assert match is not None
replacement = f"{match.group(1)} {canonical}"
if replacement == block.text:
return None, None
return (
replacement,
Operation(
type="RENAME_HEADING",
signal="semantic_robustness",
block_id=block.id,
quote=block.text,
replacement=replacement,
target_section=key,
),
)
def _split_explicit_requirements(
block: BodyBlock,
) -> tuple[str | None, Operation | None]:
if block.kind not in {"paragraph", "list_item"} or not re.search(
r"[;;]", block.text
):
return None, None
if not re.search(
r"\bMUST(?:\s+NOT)?\b|必须|不得|禁止|仅可|只能|不能", block.text, re.I
):
return None, None
parts = [part.strip() for part in re.split(r"[;;]", block.text) if part.strip()]
if len(parts) < 2:
return None, None
replacement = "\n".join(_format_payload(part) for part in parts)
return (
replacement,
Operation(
type="SPLIT_AT_EXISTING_DELIMITER",
signal="semantic_robustness",
block_id=block.id,
quote=block.text,
replacement=replacement,
),
)
def _is_standalone_rule(block: BodyBlock, quote: str) -> bool:
clean = quote.strip()
if block.kind not in {"paragraph", "list_item"}:
return False
if clean != block.text.strip():
return False
if clean.endswith((":", ":", "-", "—")):
return False
content = re.sub(r"^(?:[-+*]|\d+[.)])\s+", "", clean)
return len(content) >= 6
def _already_emphasized(block_text: str, quote_offset: int, quote: str) -> bool:
stripped = quote.strip()
stripped = re.sub(r"^(?:[-+*]|\d+[.)])\s+", "", stripped)
if stripped.startswith(("**", "__")) and stripped.endswith(("**", "__")):
return True
quote_end = quote_offset + len(quote)
for delimiter in ("**", "__"):
if (
block_text[max(0, quote_offset - len(delimiter)) : quote_offset]
== delimiter
and block_text[quote_end : quote_end + len(delimiter)] == delimiter
):
return True
return False
def _already_structurally_prominent(block: BodyBlock, quote: str) -> bool:
if PROMINENT_RULE_HEADING_RE.search(block.parent_heading or ""):
return True
return bool(PROMINENT_RULE_LABEL_RE.search(quote.strip()))
def _safe_to_emphasize(quote: str) -> bool:
# Wrapping a span that already contains emphasis creates ambiguous nested
# Markdown such as **use a **priority cascade**:**.
return not re.search(r"\*\*|__", quote)
def _emphasize(quote: str) -> str:
match = re.match(r"^((?:[-+*]|\d+[.)])\s+)(.+)$", quote.strip(), re.S)
if match:
return f"{match.group(1)}**{match.group(2)}**"
return f"**{quote.strip()}**"
def _apply_patches(body: str, patches: list[_Patch]) -> str:
ordered = sorted(patches, key=lambda item: (item.start, item.end), reverse=True)
last_start = len(body) + 1
result = body
for patch in ordered:
if patch.start < 0 or patch.end < patch.start or patch.end > len(body):
raise RewriteError("rewrite patch is outside the Markdown body")
if patch.end > last_start:
raise RewriteError("rewrite patches overlap")
result = result[: patch.start] + patch.replacement + result[patch.end :]
last_start = patch.start
return result
def _create_section_signal(key: str) -> str:
annotation_type = next(
annotation_type
for annotation_type, target in ANNOTATION_TARGET.items()
if target == key
)
return ANNOTATION_SIGNAL[annotation_type]
def rewrite_document(
document: SkillDocument,
signals: dict[str, Signal],
annotations: list[Annotation],
*,
reserved_block_ids: set[str] | None = None,
) -> tuple[str, list[Operation]]:
blocks = [replace(block) for block in document.blocks]
by_id = {block.id: block for block in blocks}
operations: list[Operation] = []
patches: list[_Patch] = []
reserved = reserved_block_ids or set()
patched_blocks: set[str] = set(reserved)
payloads: dict[str, list[str]] = defaultdict(list)
robustness = signals["semantic_robustness"]
if robustness.level in {"low", "medium"}:
for block in blocks:
if block.kind != "heading":
continue
replacement, operation = _normalize_known_heading(
block, document.language
)
if replacement is not None and operation is not None:
patches.append(
_Patch(
block.start_offset,
block.start_offset + len(block.text),
replacement,
)
)
patched_blocks.add(block.id)
operations.append(operation)
for annotation in annotations:
signal_name = ANNOTATION_SIGNAL.get(annotation.type)
if signal_name is None or not _enabled(signals[signal_name], annotation):
continue
block = by_id.get(annotation.block_id)
if block is None or annotation.quote not in block.text:
continue
if block.id in reserved:
continue
quote_offset = block.text.find(annotation.quote)
absolute_start = block.start_offset + quote_offset
absolute_end = absolute_start + len(annotation.quote)
if annotation.type == "coreference":
if (
robustness.level != "low"
or annotation.antecedent_quote is None
or block.id in patched_blocks
):
continue
patches.append(
_Patch(absolute_start, absolute_end, annotation.antecedent_quote)
)
patched_blocks.add(block.id)
operations.append(
Operation(
type="REPLACE_COREFERENCE_WITH_SOURCE_QUOTE",
signal=signal_name,
annotation_type=annotation.type,
block_id=block.id,
quote=annotation.quote,
replacement=annotation.antecedent_quote,
)
)
continue
target = ANNOTATION_TARGET[annotation.type]
if section_key(block.parent_heading) == target:
continue
if _already_structurally_prominent(block, annotation.quote):
continue
# If the exact rule already occurs more than once, a prior compilation
# has already added a summary copy. This makes compilation idempotent.
if document.body.count(annotation.quote) > 1:
continue
if _is_standalone_rule(block, annotation.quote):
formatted = _format_payload(annotation.quote)
if formatted not in payloads[target]:
payloads[target].append(formatted)
operations.append(
Operation(
type="DUPLICATE_EXACT",
signal=signal_name,
annotation_type=annotation.type,
block_id=block.id,
quote=annotation.quote,
replacement=formatted,
target_section=target,
)
)
continue
# Context-dependent fragments stay where they are. Critical directives
# get local Markdown emphasis; other non-standalone semantic fragments
# are left untouched.
if (
annotation.type in LOCAL_EMPHASIS_TYPES
and not _already_emphasized(
block.text, quote_offset, annotation.quote
)
and _safe_to_emphasize(annotation.quote)
and block.id not in patched_blocks
):
replacement = _emphasize(annotation.quote)
patches.append(_Patch(absolute_start, absolute_end, replacement))
patched_blocks.add(block.id)
operations.append(
Operation(
type="EMPHASIZE_IN_PLACE",
signal=signal_name,
annotation_type=annotation.type,
block_id=block.id,
quote=annotation.quote,
replacement=replacement,
target_section=target,
)
)
if robustness.level == "low":
for block in blocks:
if block.id in patched_blocks:
continue
replacement, operation = _split_explicit_requirements(block)
if replacement is not None and operation is not None:
patches.append(
_Patch(
block.start_offset,
block.start_offset + len(block.text),
replacement,
)
)
patched_blocks.add(block.id)
operations.append(operation)
existing_sections: dict[str, BodyBlock] = {}
for block in blocks:
if block.kind == "heading":
key = section_key(_heading_text(block))
if key is not None:
existing_sections[key] = block
insertions: dict[int, list[str]] = defaultdict(list)
new_pre_sections: list[str] = []
completion_section: str | None = None
for key in PRE_SECTION_ORDER + ("completion_criterion",):
values = payloads.get(key, [])
if not values:
continue
if key in existing_sections:
heading = existing_sections[key]
insertions[heading.end_offset].append(
document.newline + document.newline.join(values) + document.newline
)
continue
section = (
f"## {_section_heading(key, document.language)}"
f"{document.newline}{document.newline}"
+ document.newline.join(values)
)
operations.append(
Operation(
type="CREATE_SECTION",
signal=_create_section_signal(key),
target_section=key,
)
)
if key == "completion_criterion":
completion_section = section
else:
new_pre_sections.append(section)
if new_pre_sections:
first_h2 = next(
(
block
for block in blocks
if block.kind == "heading" and (block.heading_level or 0) >= 2
),
None,
)
if first_h2 is not None:
position = first_h2.start_offset
text = (
(document.newline * 2).join(new_pre_sections)
+ document.newline
+ document.newline
)
else:
first_h1 = next(
(
block
for block in blocks
if block.kind == "heading" and block.heading_level == 1
),
None,
)
position = first_h1.end_offset if first_h1 is not None else 0
text = (
document.newline
+ (document.newline * 2).join(new_pre_sections)
+ document.newline
+ document.newline
)
insertions[position].append(text)
if completion_section is not None:
prefix = "" if document.body.endswith(document.newline * 2) else document.newline
insertions[len(document.body)].append(
prefix + completion_section + document.newline
)
for position, values in insertions.items():
patches.append(_Patch(position, position, "".join(values)))
if not operations:
return document.original, []
body = _apply_patches(document.body, patches)
return document.frontmatter + body, operations