Proposal type × strategy × history matrix — audit, canonicalize, and validate all 7 types
Background
There are 7 first-class proposal types in ProposalType (musehub/models/musehub.py:798). The UI currently shows the type badge in the proposal hero but all real-world MPs have been state_merge. We have never manually exercised the other 6 types, nor validated that every combination of type × merge_strategy × history mode renders and behaves correctly.
This is a prerequisite for rc11 confidence. Before we can call the proposal system production-ready, every type must be exercised.
The 7 types:
| Type | Intended semantics |
|---|---|
state_merge |
Standard branch merge — code, content, any domain |
stem_integration |
Audio stems integrated into an arrangement |
midi_evolution |
MIDI phrase evolution |
payment_settlement |
MPay / blockchain settlement |
agent_delegation |
Agent identity or capability delegation |
identity_transition |
Identity key rotation or ownership transfer |
canonical_release |
Promoting state to a canonical / released version |
Valid merge strategies (MergeStrategy enum, post-0070 canonical names):
overlay · weave · replay · selective · cherry_pick
Valid history modes (--history flag on merge):
merge (preserve branch topology) · squash (flatten to one commit) · rebase (linear replay)
Phase 1 — Define the valid matrix
Document which strategy + history combinations are semantically valid per proposal type. Not all combinations make sense: a payment_settlement proposal should not be squashed; a stem_integration might always use overlay. Produce a canonicalized matrix:
type | valid strategies | valid history modes
---------------------|---------------------------|---------------------
state_merge | all | merge, squash, rebase
stem_integration | overlay, weave | merge, squash
midi_evolution | overlay, weave, replay | merge, squash
payment_settlement | overlay | merge
agent_delegation | overlay | merge
identity_transition | overlay | merge
canonical_release | overlay, replay | merge
Capture this as a constant in musehub/models/musehub.py (or a policy module). The API and UI should reject invalid combinations with a 422 and a clear error.
Phase 2 — Canonical naming cleanup (cross-ref issue #20 phase 3)
The stored proposal_type value is still state_merge (the legacy state_* prefix form). The other 6 types would be stored as stem_integration, midi_evolution, etc. — already without the state_ prefix. This asymmetry needs resolving before the matrix work begins.
Options:
- A: rename
STATE_MERGE → MERGE/state_merge → merge(matches the canonical pattern of the other types) + migration - B: rename all types to have consistent prefix —
code_merge,audio_stem, etc.
Recommendation: Option A. All other types are already clean short names; state_merge is the outlier. Migration: UPDATE musehub_proposals SET proposal_type = 'merge' WHERE proposal_type = 'state_merge'.
After migration, update:
ProposalType.STATE_MERGE → ProposalType.MERGE(value"merge")- DB default:
server_default="merge" - MCP dispatcher default:
"merge" - All template references
Phase 3 — Manual validation run (all 7 types)
Create one MP per proposal type against a scratch repo on staging. For each MP, exercise at least 2 strategy × history combinations. Checklist:
[ ] state_merge × overlay × merge → hero badge, strategy chip, history mode
[ ] state_merge × replay × squash → squash commit in log
[ ] state_merge × weave × rebase → linear history
[ ] stem_integration × overlay × merge
[ ] stem_integration × weave × squash
[ ] midi_evolution × overlay × merge
[ ] midi_evolution × replay × merge
[ ] payment_settlement × overlay × merge
[ ] agent_delegation × overlay × merge
[ ] identity_transition × overlay × merge
[ ] canonical_release × overlay × merge
[ ] canonical_release × replay × merge
For each: verify the proposal hero renders the correct type badge, strategy chip appears after merge, history mode is reflected in the commit log.
Phase 4 — API validation gates
Add server-side validation in create_proposal and update_proposal:
- Reject unknown
proposal_typevalues with 422 - Reject strategy + history combinations that are invalid for the given type (per Phase 1 matrix)
- Return structured errors:
{"error": "invalid_combination", "type": "payment_settlement", "strategy": "replay", "reason": "payment_settlement proposals must use overlay strategy"}
Tests: one RED test per invalid combination before implementation, GREEN after.
Phase 5 — UI type-aware rendering
The proposal hero should render differently per type:
- Type badge color/icon varies by type (not just
state_mergealways looking the same) - Strategy chip should only appear for types where it is meaningful
- For
payment_settlementandidentity_transition, show a warning banner on the merge button (irreversible operations) canonical_releaseshould display the release tag it will create
Designs should go through gabriel before implementation.