core/docs/analysis/pr837-lookback-2026-06-20.md
Shay fbccb2a298
feat(kernel): route proportional-decrease through construction proposals (#837)
* feat(kernel): route proportional-decrease through construction proposals

* docs: clarify PR #837 scope in lookback
2026-06-20 11:52:02 -07:00

42 lines
3.1 KiB
Markdown

# PR #837 Lookback — feat(kernel): route proportional-decrease through construction proposals
This lookback documents the design rationale, implementation details, and verification results for routing the proportional-decrease diagnostic path through typed `ConstructionProposal` objects.
## Rationale & Design Choices
### 1. Attaching `proposals` to `ProblemFrame`
We introduced the `proposals` field (`tuple[ConstructionProposal, ...]`) directly on the `ProblemFrame` class. This allows the frame representation to carry its candidate construction traces, linking surface evidence to the construction-affordance catalog in a self-contained manner.
### 2. Integration in `build_problem_frame`
To avoid circular imports and keep `ProblemFrameBuilder` clean, the proposals are attached in `build_problem_frame()` via a two-pass assembly:
1. Build the initial `ProblemFrame` with basic attributes.
2. Call `assess_contracts()` on the initial frame to retrieve `ContractAssessment` objects.
3. For each assessment whose candidate organ maps to a catalog family (via `get_contract_family_id()`), construct a `ConstructionProposal` via `make_proposal()`.
4. Recreate the `ProblemFrame` with the proposals tuple attached using `dataclasses.replace()`.
### 3. Exposing Public Accessors
We added the public helper `get_contract_family_id(candidate_organ: str) -> str | None` in `generate/problem_frame_contracts.py`. This avoids exposing the private mapping dict `_CONTRACT_REGISTRY` to external modules or test suites.
### 4. Scope & Boundary Clarification
PR #837 attaches assessment-backed proposal traces to `ProblemFrame` as a diagnostic trace. It does *not* make construction proposals drive relation binding or contract assessment, which remain decoupled at this stage.
## Tests Added
We introduced a dedicated test file `tests/test_proportional_decrease_proposal.py` covering:
- **Proposal trace existence**: Verifies that a `proportional_change.decrease_to_fraction` proposal is generated for proportional-decrease cases.
- **Exact evidence spans**: Asserts that proposal evidence spans correctly slice the original problem text.
- **Catalog alignment**: Verifies the proposal family ID, relation type, and candidate organ align with the catalog definition using public accessors.
- **Diagnostic-only constraints**: Validates that the underlying family has `diagnostic_only=True` and `serving_allowed=False`.
- **Blocked case handling**: Asserts that `FINAL_VALUE_CONFUSER` (a final-value question instead of a decrease-delta question) still produces a proposal trace but has a blocked status (not `"closed"`) and identifies `delta_decrease_target_unbound`.
- **Confuser exclusion**: Verifies that `AFFINE_CONFUSER` produces no proportional-decrease proposal trace.
## Verification Results
- All 54 tests pass successfully.
- Parity of adequacy metrics verified:
- Train runnable contracts remain `2` (`0005`, `0046`).
- Holdout runnable contracts remain `0`.
- Serving counts verified:
- Train: `30 correct / 20 refused / 0 wrong` (wrong_ids: `[]`)
- Holdout: `5 correct / 495 refused / 0 wrong` (wrong_ids: `[]`)