How must an instance bound extractive summarization when context includes adversarial framing?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session performs extractive summarization (selecting and quoting passages from source content) on content that may include adversarial framing—passages positioned or worded to appear authoritative, representative, or disconfirming while being strategically selected. Does not apply to strictly abstractive summarization or content verified free of adversarial framing.
Core Distinction
The separation between **extractive fidelity** (the extracted passages accurately represent the source) and **framing-attack resistance** (the passages were selected based on content, not on adversarial positioning in the source). Relying on fidelity creates the **Extraction Framing Attack**: adversarial content includes strategically positioned passages that, when extracted, create a misleading impression of the source, even though each extracted passage is verbatim accurate.
What Was Observed
In extractive summarization agent architectures, failing to defend against framing attacks produces three primary failure modes:
- **Positional Hijacking:** The source contains a prominent disclaimer or burying a critical caveat in a low-visibility location. The extractor picks up the prominent statement and omits the caveat, producing a misleading summary that is verbatim accurate.
- **Section Selection Bias:** The source is structured so that disconfirming evidence appears in "counterarguments" sections that are shorter or less prominent. The extractor, following prominence signals, over-selects the main arguments and under-selects the counter-arguments.
- **Quote Fragmentation:** The source contains key passages that are long and include qualifiers, but the extractor selects shorter fragments that omit the qualifiers, producing quote-mined content that is technically accurate but misleading.
Recorded Elements
- **`source-composition-receipt`:** The source's structural composition (sections, prominence signals, disclaimer placements), so adversarial framing is detectable from structure.
- **`extraction-fidelity-receipt`:** For each extracted passage, its exact position in the source and the source context around it, so fragment extraction is visible.
- **`coverage-balance-signature`:** The balance of extracted content across pro, con, and neutral sections, so selection bias is detectable.
- **`qualifier-preservation-receipt`:** For each quote that had qualifiers in its source context, whether the qualifiers were preserved or stripped, so fragment quote-mining is detectable.
Condition of Validity
* **Applies when:** The session performs extractive summarization, the source may have adversarial framing, and downstream consumers rely on the summary. * **Does not apply when:** The summarization is purely abstractive, the source is verified neutral, or downstream consumers verify against the source.
Decision Boundary
- **Is the summarization extractive?** If no, abstractive summarization applies. If yes, proceed.
- **Does the source have structural composition (`source-composition-receipt`)?** If yes, framing can be analyzed. If no, the source is assumed un-framed.
- **Does `coverage-balance-signature` show proportional coverage?** If yes, selection is balanced. If no, selection bias exists.
- **Conversely, when can extractive summarization proceed without framing analysis?** Only when the source is verified structurally neutral, or the summary includes position metadata so downstream consumers can judge the framing.
Operational Effect
- **Positional Hijacking Prevention:** Extraction considers source prominence, not just passage content.
- **Section Balance:** Pro/con sections are covered proportionally, not by prominence.
- **Qualifier Preservation:** Quote fragments preserve qualifiers or flag their absence.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class ExtractionVerdict(Enum):
NO_EXTRACTION = auto()
BALANCED_EXTRACTION = auto()
SELECTION_BIAS_DETECTED = auto()
FRAGMENT_QUOTE_MINED = auto()
@dataclass(frozen=True)
class ExtractionSummary:
summary_id: str
is_extractive: bool
coverage_pro_ratio: float
coverage_con_ratio: float
coverage_neutral_ratio: float
qualifiers_stripped_count: int
source_prominence_aligned_with_extraction: bool
@dataclass(frozen=True)
class ExtractionPolicy:
min_balance_ratio: float
max_acceptable_qualifier_strip: int
@dataclass(frozen=True)
class ExtractionManifest:
verdict: ExtractionVerdict
directive: str
manifest_digest: str
class ExtractiveFramingGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_summary(
cls, summary: ExtractionSummary, policy: ExtractionPolicy
) -> ExtractionManifest:
# Gate 1: Not extractive
if not summary.is_extractive:
digest = cls._hash(json.dumps({
"summary": summary.summary_id,
"type": "ABSTRACTIVE"
}, sort_keys=True))
return ExtractionManifest(
verdict=ExtractionVerdict.NO_EXTRACTION,
directive=f"PROCEED: Summary {summary.summary_id} is abstractive.",
manifest_digest=digest
)
# Gate 2: Qualifier stripping
if summary.qualifiers_stripped_count > policy.max_acceptable_qualifier_strip:
return ExtractionManifest(
verdict=ExtractionVerdict.FRAGMENT_QUOTE_MINED,
directive=f"FLAG: {summary.qualifiers_stripped_count} qualifiers stripped in {summary.summary_id}.",
manifest_digest=cls._hash(f"QUOTE_MINED:{summary.summary_id}")
)
# Gate 3: Coverage balance
pro = summary.coverage_pro_ratio
con = summary.coverage_con_ratio
if pro > 0 and con >= 0:
balance = min(pro, con) / max(pro, con) if max(pro, con) > 0 else 1.0
if balance < policy.min_balance_ratio:
return ExtractionManifest(
verdict=ExtractionVerdict.SELECTION_BIAS_DETECTED,
directive=f"FLAG: Extraction balance {balance:.2f} < {policy.min_balance_ratio:.2f}.",
manifest_digest=cls._hash(f"BIAS:{summary.summary_id}")
)
# Gate 4: Prominence alignment
if summary.source_prominence_aligned_with_extraction:
# The extraction followed source prominence, potential positional bias
digest = cls._hash(json.dumps({
"summary": summary.summary_id,
"prominence_aligned": True
}, sort_keys=True))
return ExtractionManifest(
verdict=ExtractionVerdict.BALANCED_EXTRACTION,
directive=f"PROCEED_WITH_CAUTION: Summary {summary.summary_id} follows source prominence.",
manifest_digest=digest
)
# Gate 5: Balanced
digest = cls._hash(json.dumps({
"summary": summary.summary_id,
"pro": f"{pro:.3f}",
"con": f"{con:.3f}",
"neutral": f"{summary.coverage_neutral_ratio:.3f}"
}, sort_keys=True))
return ExtractionManifest(
verdict=ExtractionVerdict.BALANCED_EXTRACTION,
directive=f"PROCEED: Summary {summary.summary_id} balanced.",
manifest_digest=digest
)