# PR #836 Lookback — feat(kernel): introduce construction-affordance catalog skeleton This lookback documents the design rationale, implementation details, and verification results for the initial slice of the construction-affordance catalog skeleton. ## Rationale & Design Choices ### 1. Catalog Registry is Diagnostic-Only Every entry in `generate/construction_affordances.py` is configured with `diagnostic_only=True` and `serving_allowed=False`. This enforces a clean trust boundary: - Candidate structures and affordances can be registered, introspected, and traced diagnostically. - The runtime serving path remains completely untouched and isolated, preventing any serving-time regressions. ### 2. Separation of Registry and Dispatch Logic The contract assessment functions (`assess_fraction_decrease` and `assess_percent_partition` in `generate/problem_frame_contracts.py`) contain construction-specific structural logic, role bindings, and hazard checks. - We introduced `_CONTRACT_REGISTRY` to map candidate organs to catalog entries. - To prevent a leaky abstraction and forced interfaces, the actual dispatch in `assess_contracts()` remains explicit and structural, but references the catalog metadata where applicable. - This ensures the registry remains a metadata/introspection layer describing *what* a construction means, while the assessment functions describe *how* its obligations are proven. ### 3. Question-Target Priority Cascade We documented the priority cascade inside `_bound_question_target` (in `generate/problem_frame_builder.py`). This prevents order-fragility in future additions: 1. Specific regex-based triggers (e.g. `_DECREASE_DELTA_QUESTION_RE` for proportional decrease delta). 2. General question clause extraction via `_QUESTION_ENTITY_RE` (or fallback to unresolved if `?` is present). 3. Clause-level target classification (e.g. `more` -> difference, `originally` -> initial, `left` -> final, etc.). ## Closed Test Gaps We successfully added targeted test coverage to `tests/test_problem_frame_contracts.py` to close all outstanding edge cases from the proportional-change proof of concept: - **Scale boundary rejection**: Rejects scale values of 0 (`0/4`), 1 (`4/4`), or greater than 1 (`5/4`) with a `scale_out_of_range` blocker. - **Multi-base rejection**: Ensures multiple candidate relations trigger `decrease_relation_ambiguous`. - **State entity continuity**: Rejects cases where the state entity in the relation differs from the target entity of the question, triggering `state_entity_continuity_unproven`. - **Unit continuity**: Rejects cases where the base quantity unit does not match the relation unit, triggering `unit_continuity_unproven`. - **Percent-partition blocker specificity**: Asserts that unequal-partition confusers correctly surface `partition_subgroups_not_distinct` and `percent_subgroup_links_incomplete`. ## Verification Results - All 46 tests across the targeted test suite pass successfully in `< 0.5s`. - Catalog behavior verified by new dedicated tests in `tests/test_construction_affordances.py`.