Spaces:
Running
Running
A5-R3-R7-R1 English section structural ownership + seal continuity
#116
by GuXiaopeng - opened
- core/generation_runner.py +61 -0
core/generation_runner.py
CHANGED
|
@@ -917,6 +917,52 @@ class GenerationRunner:
|
|
| 917 |
return ''
|
| 918 |
return f"# {title}\n" + match.group(1).strip()
|
| 919 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 920 |
@staticmethod
|
| 921 |
def _english_prefix_through_top_level(manuscript: str, title: str) -> str:
|
| 922 |
value = str(manuscript or '')
|
|
@@ -4629,6 +4675,21 @@ The previous attempt for this same manuscript unit was rejected by validation. R
|
|
| 4629 |
state.pop("section_retry_exhausted", None)
|
| 4630 |
break
|
| 4631 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4632 |
# Recompute citation survival/claim demand from the exact text that
|
| 4633 |
# will be sealed, not from an earlier pre-cleanup intermediate.
|
| 4634 |
if not is_quarantined and section_id in self._citation_eligible_section_ids(mode):
|
|
|
|
| 917 |
return ''
|
| 918 |
return f"# {title}\n" + match.group(1).strip()
|
| 919 |
|
| 920 |
+
@staticmethod
|
| 921 |
+
def _normalize_orchestrator_owned_headings(text: str, task: dict) -> str:
|
| 922 |
+
"""Restore immutable H1/H2 structure after any model-owned repair path.
|
| 923 |
+
|
| 924 |
+
Writer and repair models own prose only. The orchestrator owns the
|
| 925 |
+
expected top-level and subsection headings described by the generation
|
| 926 |
+
task. This deterministic normalizer removes only exact markdown
|
| 927 |
+
heading lines for those owned titles, then restores the canonical
|
| 928 |
+
heading(s) required for this unit. All non-heading text is preserved.
|
| 929 |
+
|
| 930 |
+
The operation is intentionally idempotent: N(N(x)) == N(x).
|
| 931 |
+
"""
|
| 932 |
+
value = str(text or "")
|
| 933 |
+
task = dict(task or {})
|
| 934 |
+
section_title = str(task.get("section") or "").strip()
|
| 935 |
+
subsection_title = str(task.get("subsection") or "").strip()
|
| 936 |
+
section_first = bool(task.get("section_first")) and bool(section_title)
|
| 937 |
+
subsection_first = bool(task.get("subsection_first")) and bool(subsection_title)
|
| 938 |
+
|
| 939 |
+
owned_titles = [title for title in (section_title, subsection_title) if title]
|
| 940 |
+
if not owned_titles:
|
| 941 |
+
return value
|
| 942 |
+
|
| 943 |
+
patterns = [
|
| 944 |
+
re.compile(rf"^[ \\t]*#{{1,6}}[ \\t]+{re.escape(title)}[ \\t]*$")
|
| 945 |
+
for title in owned_titles
|
| 946 |
+
]
|
| 947 |
+
kept_lines = []
|
| 948 |
+
for line in value.splitlines(keepends=True):
|
| 949 |
+
visible = line.rstrip("\r\n")
|
| 950 |
+
if any(pattern.fullmatch(visible) for pattern in patterns):
|
| 951 |
+
continue
|
| 952 |
+
kept_lines.append(line)
|
| 953 |
+
body = "".join(kept_lines).lstrip("\r\n")
|
| 954 |
+
|
| 955 |
+
canonical = []
|
| 956 |
+
if section_first:
|
| 957 |
+
canonical.append(f"# {section_title}")
|
| 958 |
+
if subsection_first:
|
| 959 |
+
canonical.append(f"## {subsection_title}")
|
| 960 |
+
if not canonical:
|
| 961 |
+
return body
|
| 962 |
+
|
| 963 |
+
prefix = "\n\n".join(canonical)
|
| 964 |
+
return prefix if not body else prefix + "\n\n" + body
|
| 965 |
+
|
| 966 |
@staticmethod
|
| 967 |
def _english_prefix_through_top_level(manuscript: str, title: str) -> str:
|
| 968 |
value = str(manuscript or '')
|
|
|
|
| 4675 |
state.pop("section_retry_exhausted", None)
|
| 4676 |
break
|
| 4677 |
|
| 4678 |
+
# R7-R1: heading structure is orchestrator-owned, not model-owned.
|
| 4679 |
+
# Any adaptive repair may replace the accepted prose bytes and drop
|
| 4680 |
+
# or duplicate the system-inserted H1/H2. Restore only those exact
|
| 4681 |
+
# structural anchors after the final model-owned repair and before
|
| 4682 |
+
# the unit is appended to the immutable English source / Section Seal.
|
| 4683 |
+
normalized_en_resolved = self._normalize_orchestrator_owned_headings(en_resolved, sec)
|
| 4684 |
+
if normalized_en_resolved != en_resolved:
|
| 4685 |
+
logging.info("Deterministic English heading normalization | unit=%s", display_name)
|
| 4686 |
+
quality_diagnostics.append({
|
| 4687 |
+
"scope": "english_structural_ownership",
|
| 4688 |
+
"name": display_name,
|
| 4689 |
+
"status": "deterministic_heading_normalization",
|
| 4690 |
+
})
|
| 4691 |
+
en_resolved = normalized_en_resolved
|
| 4692 |
+
|
| 4693 |
# Recompute citation survival/claim demand from the exact text that
|
| 4694 |
# will be sealed, not from an earlier pre-cleanup intermediate.
|
| 4695 |
if not is_quarantined and section_id in self._citation_eligible_section_ids(mode):
|