ADR-0184 §7 S4: add generate/derivation/state/source.py — the single boundary through which semantic-ledger worlds become pool candidates — and swap pool.py's accumulation source to semantic_state_candidates(). accumulate.py keeps its public surfaces as thin compatibility wrappers (ADR-0184 §10). Byte-identical over the 937-problem differential; verify.py / pool.py remain the sole commit authority (structural no-authority-import scan over state/, non-vacuous). Also: docs/analysis design note for the S3–S5 boundary stack, and a drive-by ruff F541 fix in r1_reconstruction.py (rf->r, zero behavior).
64 lines
3.2 KiB
Python
64 lines
3.2 KiB
Python
"""ADR-0178 GB-3b.1 — single-referent accumulation chaining.
|
|
|
|
The first cross-clause *comprehension* reading: one actor's quantity changes over
|
|
successive clauses (``Sam has 14 apples. He buys 9 more.`` -> ``14 + 9``). It is
|
|
the safe specialisation of the cross-clause sum that GB-3a's referent guard
|
|
correctly refuses wholesale (the ``Alice has 6 … Tom has 2 …`` hazard): we chain
|
|
across clauses **only** when (a) the later clause stays on the **same referent**
|
|
and (b) it carries a **licensed change cue** whose polarity is unambiguous.
|
|
Otherwise we refuse — the guard is generalised, never weakened.
|
|
|
|
ADR-0184 S1 extracted the reusable referent and change-cue helpers into
|
|
``generate.derivation.state``; S2 routed both accumulation readings through the
|
|
semantic ledger (SET/GAIN/LOSS over one entity/unit key) with replay back to
|
|
``GroundedDerivation``; §7 S4 moved world enumeration into the candidate-source
|
|
boundary, :mod:`generate.derivation.state.source`. This module remains the public
|
|
accumulation composer surface — :func:`compose_accumulation` (the gated strict
|
|
reading) and :func:`accumulation_candidates` (a thin compatibility wrapper over
|
|
:func:`generate.derivation.state.source.semantic_state_candidates`, per ADR-0184
|
|
§10). Behavior is intentionally unchanged, and every candidate still faces the
|
|
unchanged verifier/pool.
|
|
|
|
Sealed (no ``chat/`` import); deterministic; refuse-preferring.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from generate.derivation.model import GroundedDerivation
|
|
from generate.derivation.state.replay import replay_accumulation_ledger
|
|
from generate.derivation.state.source import accumulation_world, semantic_state_candidates
|
|
from generate.derivation.verify import Resolution, select_self_verified
|
|
|
|
|
|
def _build_accumulation(
|
|
problem_text: str, *, drop_isolated_foreign: bool
|
|
) -> GroundedDerivation | None:
|
|
"""Construct the single-referent accumulation chain (ungated) — build the
|
|
semantic world at the S4 boundary, replay through the S2 bridge."""
|
|
ledger = accumulation_world(problem_text, drop_isolated_foreign=drop_isolated_foreign)
|
|
if ledger is None:
|
|
return None
|
|
return replay_accumulation_ledger(ledger)
|
|
|
|
|
|
def compose_accumulation(problem_text: str) -> Resolution | None:
|
|
"""GB-3b.1 composer — single-referent gain/loss accumulation. Refuse-preferring.
|
|
|
|
The strict (commit) reading: it gates the no-distractor-skip derivation through
|
|
the unchanged self-verification gate. Behavior is byte-identical to pre-ADR-0182.
|
|
"""
|
|
derivation = _build_accumulation(problem_text, drop_isolated_foreign=False)
|
|
if derivation is None:
|
|
return None
|
|
return select_self_verified([derivation], problem_text, target_units=())
|
|
|
|
|
|
def accumulation_candidates(problem_text: str) -> tuple[GroundedDerivation, ...]:
|
|
"""ADR-0182 — the ungated accumulation readings for cross-composer pooling.
|
|
|
|
Compatibility wrapper (ADR-0184 §10): the enumeration lives at the semantic
|
|
candidate-source boundary and is byte-identical to the pre-S4 behavior — three
|
|
readings (strict, distractor-skip, anchor-skip), ungated, deterministic order,
|
|
de-dup left to the pool.
|
|
"""
|
|
return semantic_state_candidates(problem_text)
|