Follow-up from PR #264 (batch 2), surfaced while re-validating the CR cluster against the restored Add Member / Change HoH flows. Decision by Edwin 2026-08-10: file as a follow-up rather than widen #264.
Finding
_protected_content_fields() (spp_change_request_v2/models/change_request_detail_base.py) extends the post-submit freeze beyond field_to_modify only when the request type uses the field_mapping apply strategy:
protected = {"field_to_modify"}
cr_type = change_request.request_type_id
if cr_type.apply_strategy == "field_mapping":
protected |= {m.source_field for m in cr_type.apply_mapping_ids if m.source_field}
return protected
Of the 11 change-request types shipped in data/default_types.xml, only two qualify:
| Strategy |
Types |
field_mapping — fully frozen |
edit_individual, edit_group |
custom — only field_to_modify frozen |
add_member, change_hoh, remove_member, transfer_member, exit_registrant, update_id, create_group, split_household, merge_registrants |
So on a submitted or approved custom-strategy request, the detail fields the apply strategy actually reads remain writable over RPC. For the restored Add Member that is given_name, family_name, birthdate, gender_id, relationship_id, id_number, phone — and strategies/add_member.py reads exactly those to create a new res.partner and its group membership. For Change HoH it is new_head_id, new_head_membership_id, previous_head_new_role_id.
Net effect: a requester can have one thing approved and a different thing applied, for 9 of 11 types.
Not a regression
This gap existed before the #382/#871 revert too — the redesigned details were also custom-strategy. What changed is blast radius: post-revert, Add Member's apply creates a person from the unfrozen fields rather than linking an existing one. #264 is a strict improvement and should merge as-is; this issue records what it does not cover.
Suggested fix
Give _protected_content_fields() a per-detail-model override hook so a custom-strategy detail can declare its own frozen set, then implement it for the highest-value details first — spp.cr.detail.add_member and spp.cr.detail.change_hoh.
This is design work, not a patch: each custom strategy has to be read to determine which fields actually feed the apply, and apply-output fields (created_individual_id and similar) must stay writable so strategies can record their results post-approval.
Notes
Related: #264, #346.
Follow-up from PR #264 (batch 2), surfaced while re-validating the CR cluster against the restored Add Member / Change HoH flows. Decision by Edwin 2026-08-10: file as a follow-up rather than widen #264.
Finding
_protected_content_fields()(spp_change_request_v2/models/change_request_detail_base.py) extends the post-submit freeze beyondfield_to_modifyonly when the request type uses thefield_mappingapply strategy:Of the 11 change-request types shipped in
data/default_types.xml, only two qualify:field_mapping— fully frozenedit_individual,edit_groupcustom— onlyfield_to_modifyfrozenadd_member,change_hoh,remove_member,transfer_member,exit_registrant,update_id,create_group,split_household,merge_registrantsSo on a submitted or approved custom-strategy request, the detail fields the apply strategy actually reads remain writable over RPC. For the restored Add Member that is
given_name,family_name,birthdate,gender_id,relationship_id,id_number,phone— andstrategies/add_member.pyreads exactly those to create a newres.partnerand its group membership. For Change HoH it isnew_head_id,new_head_membership_id,previous_head_new_role_id.Net effect: a requester can have one thing approved and a different thing applied, for 9 of 11 types.
Not a regression
This gap existed before the #382/#871 revert too — the redesigned details were also custom-strategy. What changed is blast radius: post-revert, Add Member's apply creates a person from the unfrozen fields rather than linking an existing one. #264 is a strict improvement and should merge as-is; this issue records what it does not cover.
Suggested fix
Give
_protected_content_fields()a per-detail-model override hook so a custom-strategy detail can declare its own frozen set, then implement it for the highest-value details first —spp.cr.detail.add_memberandspp.cr.detail.change_hoh.This is design work, not a patch: each custom strategy has to be read to determine which fields actually feed the apply, and apply-output fields (
created_individual_idand similar) must stay writable so strategies can record their results post-approval.Notes
_protected_content_fields()docstring and its changelog entry, so it is not mistaken for full coverage.Related: #264, #346.