core/generate
Shay 5d1f1001f4 feat(adr-0174-phase3a): lookback re-evaluation operator + pronoun resolution substrate
ADR-0174 Phase 3a — substrate for held-hypothesis lookback.
Score unchanged at 3/47/0 (this PR is correctly-engineered
infrastructure; eval impact gated on ADR-0163.x recognizer expansion
documented in the follow-up brief).

Adds generate/comprehension/lookback.py:
- VALID_REFINEMENT_KINDS, VALID_UNRESOLVED_SLOTS — closed sets
  contracted with reader_trace consumer
- PronounResolution refinement dataclass (pronoun + resolved_to +
  evidence_source, all validated)
- Refinement Union (Phase 3b will widen with CompoundClauseExpansion)
- ReevaluateResult dataclass with admit/eliminate consistency
- reevaluate(hypothesis, refinement) operator — applies refinement,
  re-runs check_constraints, returns refined Hypothesis or None.
- _rebuild_candidate_with_resolved_actor — rebuilds
  CandidateOperation / CandidateInitial replacing the semantic actor
  field (op.actor / initial.entity) while preserving matched_actor_token
  / matched_entity_token as the pronoun (so grounding still passes
  against the held statement's source span).

Modifies generate/recognizer_match.py:
- _try_extract_discrete_count_anchor: pronoun-subject statements now
  emit anchors with subject_role=<pronoun> + requires_pronoun_resolution
  marker, rather than refusing at the _REFUSED_SUBJECT_TOKENS check.
  The other narrowness layers (clause split, verb whitelist) still
  refuse; only the pronoun layer changes.

Modifies generate/math_candidate_graph.py:
- After inject_from_match, when any parsed_anchor carries
  requires_pronoun_resolution, the candidates are held as Hypothesis
  objects with unresolved=('actor_pronoun',). The lookback path then
  resolves via the existing _discourse_prior_subjects map and runs
  PronounResolution refinements through reevaluate.  Resolved
  hypotheses flow into per_sentence_choices as if the regex parser
  had produced them; unresolved hypotheses drop cleanly (refusal-
  preferring).  Emits 'lookback' JSON trace events with
  outcome ∈ {admitted, eliminated, no_antecedent}.

Tests:
- tests/test_adr_0174_phase3_lookback.py — 17 acceptance tests
  covering operator semantics on Operation/Initial, dataclass
  invariants, closed-set constants, end-to-end wiring on synthetic
  problems, and wrong=0 preservation on train_sample.

Phase 3.1 follow-up brief:
- docs/handoff/PHASE-3.1-FOLLOWUP-RECOGNIZER-EXPANSION.md documents
  the empirical finding that the train_sample bottleneck is
  verb-coverage (recognizer scope, ADR-0163.x) not lookback
  (ADR-0174 scope). 11 verbs identified for HITL contemplation pass.
  Recommends sequencing: Phase 3a now (substrate), ADR-0163.x verb
  expansion next, Phase 3b after coverage matures.

Acceptance verified:
- 17/17 Phase 3a tests pass
- 95/95 existing tests pass (Phase 1 + Phase 2 + brief_11 + reader_phase2)
- Smoke 67/67, packs 141/141, lanes 8/8
- wrong=0 preserved, score unchanged 3/47/0 (intentional per brief)

Stacks on Phase 2 (PR #420). Rebases onto main after #416 + #420 land.
2026-05-28 10:49:20 -07:00
..
binding_graph
comprehension feat(adr-0174-phase3a): lookback re-evaluation operator + pronoun resolution substrate 2026-05-28 10:49:20 -07:00
__init__.py
admissibility.py
articulation.py
articulation_legality.py
attention.py
bridge_trace.py
dialogue.py
discourse_planner.py
exhaustion.py fix(W-011/W-012): propagate recognition refusal + catch InnerLoopExhaustion (#258) 2026-05-24 20:46:46 -07:00
graph_constraint.py
graph_planner.py
grounding_accessors.py
intent.py
intent_bridge.py
intent_ratifier.py feat(recognition): ADR-0144 — EpistemicGraph carrier + pipeline integration (#227) 2026-05-24 13:39:01 -07:00
math_candidate_graph.py feat(adr-0174-phase3a): lookback re-evaluation operator + pronoun resolution substrate 2026-05-28 10:49:20 -07:00
math_candidate_parser.py feat(RAT-1): close ratify→runtime gap + first live composition admission 2026-05-27 20:09:47 -07:00
math_parser.py chore(audit): substrate cleanup — dead spike, gitignore, deprecation, reader diagnosis 2026-05-28 07:00:33 -07:00
math_problem_graph.py fix(math-graph): refuse contradictory initial possessions (wrong=0 hazard) 2026-05-28 09:51:14 -07:00
math_realizer.py
math_roundtrip.py fix(roundtrip): multi-word units ground when every component appears in source 2026-05-28 07:49:24 -07:00
math_solver.py
math_symbolic_equivalence.py
math_symbolic_normalizer.py
math_verifier.py
morphology.py
ood_surface_generator.py fix(quarantine): drain all 60 quarantined tests — QUARANTINE=∅ (#267) 2026-05-25 11:22:12 -07:00
operators.py
perturbation_suite.py
proposition.py
realizer.py [codex] Implement energy-modulated vault surface (#269) 2026-05-25 11:33:32 -07:00
realizer_guard.py
recognizer_anchor_inject.py feat(wave-a): first non-DCS injector — multiplicative_aggregation w/ value extraction 2026-05-27 20:50:04 -07:00
recognizer_match.py feat(adr-0174-phase3a): lookback re-evaluation operator + pronoun resolution substrate 2026-05-28 10:49:20 -07:00
recognizer_registry.py feat(ADR-0163.D): wire ratified RecognizerSpecs into math_candidate_graph admissibility surface (#302) 2026-05-26 13:11:47 -07:00
result.py
rotor_admissibility.py
salience.py
semantic_templates.py
stream.py
surface.py
templates.py