Spaces:
Running
Running
Commit ·
3dfd2ee
1
Parent(s): dcc9c31
S0-R1-C5.5-R6-R5 Discussion Study Interpretation + Evidence-Limited Citation Closure (#93)
Browse files- S0-R1-C5.5-R6-R5 Discussion Study Interpretation + Evidence-Limited Citation Closure (d7abdcb1ff5ce630f6264818e5c1f6a41a261f21)
- core/generation_runner.py +40 -1
- core/pipeline_agent.py +77 -4
core/generation_runner.py
CHANGED
|
@@ -2355,6 +2355,20 @@ class GenerationRunner:
|
|
| 2355 |
else {"introduction", "theory", "methodology", "discussion"}
|
| 2356 |
)
|
| 2357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2358 |
@classmethod
|
| 2359 |
def _adaptive_citation_requirements(cls, tasks, mode: str):
|
| 2360 |
"""Derive evidence demand and semantic-survival reserve from manuscript units."""
|
|
@@ -3029,6 +3043,13 @@ class GenerationRunner:
|
|
| 3029 |
}
|
| 3030 |
for display_name, reserve_target in citation_reserve_targets.items():
|
| 3031 |
planned_items = citation_plan.setdefault(display_name, [])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3032 |
shortfall = max(0, reserve_target - len(planned_items))
|
| 3033 |
if shortfall <= 0:
|
| 3034 |
continue
|
|
@@ -3054,6 +3075,12 @@ class GenerationRunner:
|
|
| 3054 |
deficit = max(0, int(required) - int(top_level_counts.get(section_id, 0)))
|
| 3055 |
if deficit <= 0:
|
| 3056 |
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3057 |
section_units = [
|
| 3058 |
name for name, mapped in citation_unit_section_map.items() if mapped == section_id
|
| 3059 |
]
|
|
@@ -3643,6 +3670,14 @@ class GenerationRunner:
|
|
| 3643 |
"\nCURRENT-STUDY PROVENANCE RULE: Do not attach external literature citations to this study's own research question, H1-Hn statement, sample/design fact, analytic choice, result, limitation specific to the available study evidence, or author positioning. "
|
| 3644 |
"If prior literature provides a rationale, state that external rationale in a separate sentence and cite only that sentence."
|
| 3645 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3646 |
if section_id not in {"results", "findings", "appendix"}:
|
| 3647 |
citation_rule += (
|
| 3648 |
"\nATOMIC LITERATURE CLAIM CONTRACT: Write one externally verifiable proposition per sentence. "
|
|
@@ -4022,7 +4057,11 @@ The previous attempt for this same manuscript unit was rejected by validation. R
|
|
| 4022 |
|
| 4023 |
used_after = set(agent.used_citations)
|
| 4024 |
survived = used_after - used_before
|
| 4025 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4026 |
required_survival = min(
|
| 4027 |
len(attempt_assigned_tag_list),
|
| 4028 |
max(1, int(math.ceil(len(attempt_assigned_tag_list) * CITATION_SEMANTIC_SURVIVAL_RATIO))),
|
|
|
|
| 2355 |
else {"introduction", "theory", "methodology", "discussion"}
|
| 2356 |
)
|
| 2357 |
|
| 2358 |
+
@staticmethod
|
| 2359 |
+
def _quota_driven_citation_recovery_allowed(section_id: str) -> bool:
|
| 2360 |
+
"""Discussion evidence is claim-driven, never padded to a word-count target.
|
| 2361 |
+
|
| 2362 |
+
R6-R5 keeps claim-specific planner assignments, but disables reserve/JIT
|
| 2363 |
+
top-ups whose only trigger is a numeric citation target. After drafting,
|
| 2364 |
+
the existing bounded top-level completion may still attach a directly
|
| 2365 |
+
validated source to an actual external claim.
|
| 2366 |
+
"""
|
| 2367 |
+
return str(section_id or '').strip().lower() != 'discussion'
|
| 2368 |
+
|
| 2369 |
+
# Backward-readable name used by R6-R5 replay documentation.
|
| 2370 |
+
_pre_draft_citation_recovery_allowed = _quota_driven_citation_recovery_allowed
|
| 2371 |
+
|
| 2372 |
@classmethod
|
| 2373 |
def _adaptive_citation_requirements(cls, tasks, mode: str):
|
| 2374 |
"""Derive evidence demand and semantic-survival reserve from manuscript units."""
|
|
|
|
| 3043 |
}
|
| 3044 |
for display_name, reserve_target in citation_reserve_targets.items():
|
| 3045 |
planned_items = citation_plan.setdefault(display_name, [])
|
| 3046 |
+
unit_section_id = str(task_by_name.get(display_name, {}).get("section_id") or "")
|
| 3047 |
+
if not self._quota_driven_citation_recovery_allowed(unit_section_id):
|
| 3048 |
+
logging.info(
|
| 3049 |
+
"Discussion pre-draft reserve recovery skipped: unit=%s direct_plan=%s policy=claim_driven",
|
| 3050 |
+
display_name, len(planned_items),
|
| 3051 |
+
)
|
| 3052 |
+
continue
|
| 3053 |
shortfall = max(0, reserve_target - len(planned_items))
|
| 3054 |
if shortfall <= 0:
|
| 3055 |
continue
|
|
|
|
| 3075 |
deficit = max(0, int(required) - int(top_level_counts.get(section_id, 0)))
|
| 3076 |
if deficit <= 0:
|
| 3077 |
continue
|
| 3078 |
+
if not self._quota_driven_citation_recovery_allowed(section_id):
|
| 3079 |
+
logging.info(
|
| 3080 |
+
"Discussion pre-draft JIT quota top-up skipped: section=%s direct_plan=%s required=%s policy=claim_driven",
|
| 3081 |
+
section_id, int(top_level_counts.get(section_id, 0)), int(required),
|
| 3082 |
+
)
|
| 3083 |
+
continue
|
| 3084 |
section_units = [
|
| 3085 |
name for name, mapped in citation_unit_section_map.items() if mapped == section_id
|
| 3086 |
]
|
|
|
|
| 3670 |
"\nCURRENT-STUDY PROVENANCE RULE: Do not attach external literature citations to this study's own research question, H1-Hn statement, sample/design fact, analytic choice, result, limitation specific to the available study evidence, or author positioning. "
|
| 3671 |
"If prior literature provides a rationale, state that external rationale in a separate sentence and cite only that sentence."
|
| 3672 |
)
|
| 3673 |
+
if section_id == "discussion":
|
| 3674 |
+
citation_rule += (
|
| 3675 |
+
"\nDISCUSSION EVIDENCE-LIMITED CONTRACT: Distinguish prior-literature claims from study-owned interpretation. "
|
| 3676 |
+
"Statements such as 'the present evidence suggests', 'these findings indicate', or 'the present results suggest' are interpretations of this study and must not borrow an external citation. "
|
| 3677 |
+
"Do not create or broaden an external-literature claim merely to consume a citation or satisfy a citation count. "
|
| 3678 |
+
"When claim-specific literature is sparse, develop the Discussion from documented study evidence, cautious conceptual reasoning, boundary conditions, and limitations. "
|
| 3679 |
+
"If comparing with prior literature, put the directly supported prior-literature proposition in its own cited sentence and the study-owned interpretation in a separate uncited sentence."
|
| 3680 |
+
)
|
| 3681 |
if section_id not in {"results", "findings", "appendix"}:
|
| 3682 |
citation_rule += (
|
| 3683 |
"\nATOMIC LITERATURE CLAIM CONTRACT: Write one externally verifiable proposition per sentence. "
|
|
|
|
| 4057 |
|
| 4058 |
used_after = set(agent.used_citations)
|
| 4059 |
survived = used_after - used_before
|
| 4060 |
+
if (
|
| 4061 |
+
attempt_assigned_tag_list
|
| 4062 |
+
and not is_quarantined
|
| 4063 |
+
and self._quota_driven_citation_recovery_allowed(section_id)
|
| 4064 |
+
):
|
| 4065 |
required_survival = min(
|
| 4066 |
len(attempt_assigned_tag_list),
|
| 4067 |
max(1, int(math.ceil(len(attempt_assigned_tag_list) * CITATION_SEMANTIC_SURVIVAL_RATIO))),
|
core/pipeline_agent.py
CHANGED
|
@@ -3327,6 +3327,63 @@ INPUT:
|
|
| 3327 |
return 'STRUCTURAL'
|
| 3328 |
return 'EXTERNAL_LITERATURE_CLAIM'
|
| 3329 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3330 |
@classmethod
|
| 3331 |
def _citation_study_evidence_signal(cls, sentence, section_name=''):
|
| 3332 |
text = re.sub(r'\s+', ' ', str(sentence or '')).casefold().strip()
|
|
@@ -3400,9 +3457,24 @@ INPUT:
|
|
| 3400 |
clean = re.sub(r'\s*\[?CITE-\d+\]?\s*', ' ', raw, flags=re.I)
|
| 3401 |
clean = re.sub(r'\s+', ' ', clean).strip()
|
| 3402 |
base = cls._citation_base_provenance(clean, section_name)
|
|
|
|
|
|
|
|
|
|
| 3403 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3404 |
# Structural/hypothesis/positioning/result identities stay authoritative.
|
| 3405 |
-
|
| 3406 |
provenance = base
|
| 3407 |
components = [base]
|
| 3408 |
else:
|
|
@@ -3439,6 +3511,7 @@ INPUT:
|
|
| 3439 |
'METHOD_PRINCIPLE': 'METHOD_AUTHORITY',
|
| 3440 |
'EXTERNAL_LITERATURE_CLAIM': 'LITERATURE_EVIDENCE',
|
| 3441 |
'AUTHOR_INFERENCE': 'AUTHOR_REASONING',
|
|
|
|
| 3442 |
'STUDY_POSITIONING': 'AUTHOR_REASONING',
|
| 3443 |
'HYPOTHESIS_STATEMENT': 'HYPOTHESIS_CONTRACT',
|
| 3444 |
'STRUCTURAL': 'NONE',
|
|
@@ -3493,9 +3566,9 @@ INPUT:
|
|
| 3493 |
+ ', '.join(frame.get('ownership_components') or []) + '.'
|
| 3494 |
),
|
| 3495 |
'repair_instruction': (
|
| 3496 |
-
'Split the sentence by evidence ownership. State the current-study fact from the study evidence without an external citation; '
|
| 3497 |
-
'state a methodological principle separately and cite only a directly supporting METHOD_AUTHORITY source;
|
| 3498 |
-
'
|
| 3499 |
),
|
| 3500 |
})
|
| 3501 |
return rows
|
|
|
|
| 3327 |
return 'STRUCTURAL'
|
| 3328 |
return 'EXTERNAL_LITERATURE_CLAIM'
|
| 3329 |
|
| 3330 |
+
@staticmethod
|
| 3331 |
+
def _citation_discussion_section(section_id='', section_name=''):
|
| 3332 |
+
sid = str(section_id or '').strip().lower()
|
| 3333 |
+
if sid in {'discussion', 'conclusion'}:
|
| 3334 |
+
return True
|
| 3335 |
+
name = re.sub(r'[^a-z]+', ' ', str(section_name or '').lower()).strip()
|
| 3336 |
+
return bool(re.search(r'\b(?:discussion|conclusion|implications?)\b', name))
|
| 3337 |
+
|
| 3338 |
+
@staticmethod
|
| 3339 |
+
def _citation_external_literature_signal(sentence):
|
| 3340 |
+
"""High-confidence signal that a clause explicitly attributes a claim to prior literature."""
|
| 3341 |
+
text = re.sub(r'\s+', ' ', str(sentence or '')).casefold().strip()
|
| 3342 |
+
if not text:
|
| 3343 |
+
return False
|
| 3344 |
+
return bool(re.search(
|
| 3345 |
+
r'\b(?:prior|previous|existing|earlier) (?:studies|research|work|literature)|'
|
| 3346 |
+
r'\bthe (?:prior|existing|broader) literature\b|'
|
| 3347 |
+
r'\b(?:studies|researchers|scholars) (?:have )?(?:shown|show|reported|report|argued|argue|suggested|suggest|found|find|documented|document)\b|'
|
| 3348 |
+
r'\bevidence from (?:prior|previous|existing|earlier) (?:studies|research|work)\b',
|
| 3349 |
+
text, flags=re.I,
|
| 3350 |
+
))
|
| 3351 |
+
|
| 3352 |
+
@classmethod
|
| 3353 |
+
def _citation_study_interpretation_signal(cls, sentence, section_id='', section_name=''):
|
| 3354 |
+
"""Identify Discussion/Conclusion interpretations owned by this study, not by external literature.
|
| 3355 |
+
|
| 3356 |
+
R6-R5 distinguishes an interpretation of the frozen study evidence from a
|
| 3357 |
+
literature finding. The signal is deliberately narrow: it requires both a
|
| 3358 |
+
current-study anchor and an interpretive predicate in a Discussion-like unit.
|
| 3359 |
+
Pure descriptions of prior research remain literature-owned, while mixed
|
| 3360 |
+
comparison sentences are handled by the evidence-ownership splitter.
|
| 3361 |
+
"""
|
| 3362 |
+
if not cls._citation_discussion_section(section_id, section_name):
|
| 3363 |
+
return False
|
| 3364 |
+
text = re.sub(r'\s+', ' ', str(sentence or '')).casefold().strip()
|
| 3365 |
+
if not text:
|
| 3366 |
+
return False
|
| 3367 |
+
anchor = bool(re.search(
|
| 3368 |
+
r'\b(?:the present|these|our|the current) (?:evidence|findings|results)|'
|
| 3369 |
+
r'\b(?:the findings|the results|the evidence) (?:of|from|in) (?:this|the present|the current) study|'
|
| 3370 |
+
r'\bthe (?:pattern|association|associations|relationship|relationships) observed here|'
|
| 3371 |
+
r'\bthe observed (?:pattern|association|associations|relationship|relationships)|'
|
| 3372 |
+
r'\btaken together,? (?:the|these|our) (?:findings|results|evidence)|'
|
| 3373 |
+
r'\bthe emergent process model\b|'
|
| 3374 |
+
r'\bthe process model developed here\b',
|
| 3375 |
+
text, flags=re.I,
|
| 3376 |
+
))
|
| 3377 |
+
if not anchor:
|
| 3378 |
+
return False
|
| 3379 |
+
interpretive = bool(re.search(
|
| 3380 |
+
r'\b(?:suggests?|indicates?|implies?|shows?|reveals?|highlights?|points? to|qualif(?:y|ies|ied)|'
|
| 3381 |
+
r'is consistent with|are consistent with|appears? to|supports? (?:the )?interpretation|'
|
| 3382 |
+
r'warrants?|means? that|by showing)\b',
|
| 3383 |
+
text, flags=re.I,
|
| 3384 |
+
))
|
| 3385 |
+
return interpretive
|
| 3386 |
+
|
| 3387 |
@classmethod
|
| 3388 |
def _citation_study_evidence_signal(cls, sentence, section_name=''):
|
| 3389 |
text = re.sub(r'\s+', ' ', str(sentence or '')).casefold().strip()
|
|
|
|
| 3457 |
clean = re.sub(r'\s*\[?CITE-\d+\]?\s*', ' ', raw, flags=re.I)
|
| 3458 |
clean = re.sub(r'\s+', ' ', clean).strip()
|
| 3459 |
base = cls._citation_base_provenance(clean, section_name)
|
| 3460 |
+
study_interpretation = cls._citation_study_interpretation_signal(
|
| 3461 |
+
clean, section_id=section_id, section_name=section_name
|
| 3462 |
+
)
|
| 3463 |
|
| 3464 |
+
# Discussion interpretations of this study's own evidence override a
|
| 3465 |
+
# superficial RESULT/FINDING token in a subsection title. If the same
|
| 3466 |
+
# sentence also attributes a proposition to prior literature, ownership
|
| 3467 |
+
# becomes mixed and the sentence must be split before citation QA.
|
| 3468 |
+
if study_interpretation:
|
| 3469 |
+
components = []
|
| 3470 |
+
if cls._citation_external_literature_signal(clean):
|
| 3471 |
+
components.append('EXTERNAL_LITERATURE_CLAIM')
|
| 3472 |
+
components.append('STUDY_INTERPRETATION')
|
| 3473 |
+
provenance = (
|
| 3474 |
+
'MIXED_EVIDENCE_OWNERSHIP' if len(components) > 1 else 'STUDY_INTERPRETATION'
|
| 3475 |
+
)
|
| 3476 |
# Structural/hypothesis/positioning/result identities stay authoritative.
|
| 3477 |
+
elif base in {'STRUCTURAL', 'HYPOTHESIS_STATEMENT', 'STUDY_POSITIONING', 'RESULT_OWNED_FACT'}:
|
| 3478 |
provenance = base
|
| 3479 |
components = [base]
|
| 3480 |
else:
|
|
|
|
| 3511 |
'METHOD_PRINCIPLE': 'METHOD_AUTHORITY',
|
| 3512 |
'EXTERNAL_LITERATURE_CLAIM': 'LITERATURE_EVIDENCE',
|
| 3513 |
'AUTHOR_INFERENCE': 'AUTHOR_REASONING',
|
| 3514 |
+
'STUDY_INTERPRETATION': 'STUDY_EVIDENCE_LEDGER+AUTHOR_REASONING',
|
| 3515 |
'STUDY_POSITIONING': 'AUTHOR_REASONING',
|
| 3516 |
'HYPOTHESIS_STATEMENT': 'HYPOTHESIS_CONTRACT',
|
| 3517 |
'STRUCTURAL': 'NONE',
|
|
|
|
| 3566 |
+ ', '.join(frame.get('ownership_components') or []) + '.'
|
| 3567 |
),
|
| 3568 |
'repair_instruction': (
|
| 3569 |
+
'Split the sentence by evidence ownership. State the current-study fact or study-owned interpretation from the study evidence without an external citation; '
|
| 3570 |
+
'state a methodological principle separately and cite only a directly supporting METHOD_AUTHORITY source; state prior-literature claims '
|
| 3571 |
+
'in their own sentence with direct literature support; keep author inference separate and cautious.'
|
| 3572 |
),
|
| 3573 |
})
|
| 3574 |
return rows
|