# 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`.
