R14-TQ1-R1 evidence-carrying lexical-purity claim repair

#49
Files changed (1) hide show
  1. core/pipeline_agent.py +57 -6
core/pipeline_agent.py CHANGED
@@ -5453,17 +5453,36 @@ Translate headings and terminology naturally. Preserve standard variable abbrevi
5453
  restored[block_id] = recovered[block_id]
5454
  return restored
5455
 
5456
- def _translate_single_claim_with_recovery(self, block_id, claim_id, source_claim, system_prompt, target_lang, issue_codes):
5457
- """Regenerate one failed claim using bounded QA codes only."""
 
 
 
5458
  protected_claim, mapping = self._protect_translation_tokens(source_claim, claim_id=claim_id)
5459
  marked_source = f'[[SP-P{block_id}]]\n[[SP-{claim_id}]]\n{protected_claim}'
5460
  safe_manifest = self._model_safe_translation_manifest(mapping)
5461
  codes = [str(code or '').strip().upper() for code in (issue_codes or []) if str(code or '').strip()]
 
 
 
 
 
 
 
 
 
 
 
5462
  effective_prompt = system_prompt + (
5463
  '\nCLAIM QUALITY RETRY. Repair only this one claim. The only permitted repair signals are the following bounded issue codes: '
5464
  + json.dumps(codes[:5], ensure_ascii=False)
5465
- + '. Do not infer any examples or numbered instructions from those codes. Preserve every SP-P, SP-C, and SP-T marker byte-for-byte. '
5466
- 'Do not add claims or factual content. Return only the marked translated claim.'
 
 
 
 
 
5467
  + '\n<SEMANTIC_ANCHOR_MANIFEST>\n'
5468
  + json.dumps({block_id: safe_manifest}, ensure_ascii=False)
5469
  + '\n</SEMANTIC_ANCHOR_MANIFEST>'
@@ -5785,9 +5804,41 @@ Decision must be CONFIRMED_BLOCKING or NOT_CONFIRMED. evidence_code must be one
5785
  )
5786
  claim_order = list(source_claims)
5787
  _order, segments = self._parse_translation_claim_segments(translations[block_id], claim_order)
5788
- segments[claim_id] = self._translate_single_claim_with_recovery(
5789
- block_id, claim_id, source_claims[claim_id], system_prompt, target_lang, codes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5790
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5791
  translations[block_id] = self._compose_translation_claim_segments(claim_order, segments)
5792
  touched_blocks.add(block_id)
5793
  emit_stage('qa')
 
5453
  restored[block_id] = recovered[block_id]
5454
  return restored
5455
 
5456
+ def _translate_single_claim_with_recovery(
5457
+ self, block_id, claim_id, source_claim, system_prompt, target_lang, issue_codes,
5458
+ current_target_claim=None, repair_evidence=None,
5459
+ ):
5460
+ """Regenerate one failed claim using bounded QA codes plus detector evidence."""
5461
  protected_claim, mapping = self._protect_translation_tokens(source_claim, claim_id=claim_id)
5462
  marked_source = f'[[SP-P{block_id}]]\n[[SP-{claim_id}]]\n{protected_claim}'
5463
  safe_manifest = self._model_safe_translation_manifest(mapping)
5464
  codes = [str(code or '').strip().upper() for code in (issue_codes or []) if str(code or '').strip()]
5465
+ evidence_payload = {
5466
+ 'issue_codes': codes[:5],
5467
+ 'current_target_claim': str(current_target_claim or '').strip(),
5468
+ }
5469
+ supplied_evidence = dict(repair_evidence or {})
5470
+ lexical_tokens = [
5471
+ str(token or '').strip() for token in (supplied_evidence.get('detected_unprotected_english_tokens') or [])
5472
+ if str(token or '').strip()
5473
+ ]
5474
+ if lexical_tokens:
5475
+ evidence_payload['detected_unprotected_english_tokens'] = lexical_tokens[:8]
5476
  effective_prompt = system_prompt + (
5477
  '\nCLAIM QUALITY RETRY. Repair only this one claim. The only permitted repair signals are the following bounded issue codes: '
5478
  + json.dumps(codes[:5], ensure_ascii=False)
5479
+ + '. Use the bounded detector evidence below only to repair the supplied claim; do not invent additional defects. '
5480
+ 'The current target claim is context, not authority: the frozen English source remains authoritative. '
5481
+ 'If detected_unprotected_english_tokens is non-empty, every listed token is deterministic lexical-purity evidence and MUST be translated or removed from ordinary target-language prose; do not preserve it unless it is represented by a protected SP-T anchor. '
5482
+ 'Preserve every SP-P, SP-C, and SP-T marker byte-for-byte. Do not add claims or factual content. Return only the marked translated claim.'
5483
+ + '\n<CLAIM_REPAIR_EVIDENCE>\n'
5484
+ + json.dumps(evidence_payload, ensure_ascii=False)
5485
+ + '\n</CLAIM_REPAIR_EVIDENCE>'
5486
  + '\n<SEMANTIC_ANCHOR_MANIFEST>\n'
5487
  + json.dumps({block_id: safe_manifest}, ensure_ascii=False)
5488
  + '\n</SEMANTIC_ANCHOR_MANIFEST>'
 
5804
  )
5805
  claim_order = list(source_claims)
5806
  _order, segments = self._parse_translation_claim_segments(translations[block_id], claim_order)
5807
+ current_target_claim = segments[claim_id]
5808
+ repair_evidence = {}
5809
+ if 'LANGUAGE_CONTAMINATION' in {str(code or '').strip().upper() for code in (codes or [])}:
5810
+ lexical = self._translation_lexical_purity_evidence(
5811
+ source_claims[claim_id], current_target_claim, target_lang, frozen_glossary
5812
+ )
5813
+ if lexical.get('confirmed'):
5814
+ repair_evidence['detected_unprotected_english_tokens'] = list(lexical.get('tokens') or [])[:8]
5815
+ self._record_translation_assurance(
5816
+ 'LEXICAL_PURITY_REPAIR_EVIDENCE', target_lang=target_lang,
5817
+ block_id=f'SP-P{block_id}-{claim_id}', severity='repair', decision='REPAIR_LOCAL',
5818
+ detail={
5819
+ 'token_count': int(lexical.get('token_count') or 0),
5820
+ 'sample': ','.join(lexical.get('tokens') or [])[:120],
5821
+ },
5822
+ )
5823
+ repaired_claim = self._translate_single_claim_with_recovery(
5824
+ block_id, claim_id, source_claims[claim_id], system_prompt, target_lang, codes,
5825
+ current_target_claim=current_target_claim, repair_evidence=repair_evidence,
5826
  )
5827
+ if 'LANGUAGE_CONTAMINATION' in {str(code or '').strip().upper() for code in (codes or [])}:
5828
+ post_repair_lexical = self._translation_lexical_purity_evidence(
5829
+ source_claims[claim_id], repaired_claim, target_lang, frozen_glossary
5830
+ )
5831
+ self._record_translation_assurance(
5832
+ 'LEXICAL_PURITY_REPAIR_RESIDUAL' if post_repair_lexical.get('confirmed') else 'LEXICAL_PURITY_REPAIR_CLEARED',
5833
+ target_lang=target_lang, block_id=f'SP-P{block_id}-{claim_id}',
5834
+ severity='repair' if post_repair_lexical.get('confirmed') else 'diagnostic',
5835
+ decision='REPAIR_LOCAL' if post_repair_lexical.get('confirmed') else 'PASS_WITH_WARNING',
5836
+ detail={
5837
+ 'token_count': int(post_repair_lexical.get('token_count') or 0),
5838
+ 'sample': ','.join(post_repair_lexical.get('tokens') or [])[:120],
5839
+ },
5840
+ )
5841
+ segments[claim_id] = repaired_claim
5842
  translations[block_id] = self._compose_translation_claim_segments(claim_order, segments)
5843
  touched_blocks.add(block_id)
5844
  emit_stage('qa')