An automated review of #1189 flagged a missing cross-field invariant in the BReg lifecycle record decoder. crates/registry-breg-client/src/lifecycle.rs decodes the review projection with decode_external_review_status independently of the proposal it was decoded alongside: the only cross-check at that site is that detailErased records carry no review. The frozen proposal carries its own BRegExternalReviewRequirement { authority, policy_id }, and a proposal may declare mode: none.
Failure scenario: a payload pairs a review projection whose submission authority or accepted policy differs from the concurrently returned proposal.review requirement, or attaches a review to a mode: none proposal. Both structures decode. BRegAdapter::occurrence_state then classifies the source occurrence from a review application that did not govern the frozen proposal, so maintained clients and Casework can report completed or synchronizing work under the wrong review.
Suggested fix:
- When both
review and proposal.review are present, require the review's submission authority and accepted policy to match the requirement, and reject a review attached to a mode: none proposal.
- Add decoder unit tests for a mismatched authority, a mismatched policy, and a review on a
mode: none proposal.
Related to #1222, which covers a different invariant in the same decoder (result.state versus application.state).
Filed from the review of #1189; not merge-blocking.
An automated review of #1189 flagged a missing cross-field invariant in the BReg lifecycle record decoder.
crates/registry-breg-client/src/lifecycle.rsdecodes thereviewprojection withdecode_external_review_statusindependently of theproposalit was decoded alongside: the only cross-check at that site is thatdetailErasedrecords carry no review. The frozen proposal carries its ownBRegExternalReviewRequirement { authority, policy_id }, and a proposal may declaremode: none.Failure scenario: a payload pairs a
reviewprojection whose submission authority or accepted policy differs from the concurrently returnedproposal.reviewrequirement, or attaches a review to amode: noneproposal. Both structures decode.BRegAdapter::occurrence_statethen classifies the source occurrence from a review application that did not govern the frozen proposal, so maintained clients and Casework can report completed or synchronizing work under the wrong review.Suggested fix:
reviewandproposal.revieware present, require the review's submission authority and accepted policy to match the requirement, and reject a review attached to amode: noneproposal.mode: noneproposal.Related to #1222, which covers a different invariant in the same decoder (
result.stateversusapplication.state).Filed from the review of #1189; not merge-blocking.