@@ -14,6 +14,34 @@ pub enum KanbanTransport {
1414 A2a ,
1515}
1616
17+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq , Default ) ]
18+ #[ serde( rename_all = "lowercase" ) ]
19+ pub enum KanbanTransitionGateMode {
20+ #[ default]
21+ Blocking ,
22+ Warning ,
23+ }
24+
25+ #[ derive( Debug , Clone , Serialize , Deserialize , Default , PartialEq ) ]
26+ #[ serde( rename_all = "camelCase" ) ]
27+ pub struct KanbanContractRules {
28+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
29+ pub require_canonical_story : Option < bool > ,
30+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
31+ pub loop_breaker_threshold : Option < i64 > ,
32+ }
33+
34+ #[ derive( Debug , Clone , Serialize , Deserialize , Default , PartialEq ) ]
35+ #[ serde( rename_all = "camelCase" ) ]
36+ pub struct KanbanDeliveryRules {
37+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
38+ pub require_committed_changes : Option < bool > ,
39+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
40+ pub require_clean_worktree : Option < bool > ,
41+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
42+ pub require_pull_request_ready : Option < bool > ,
43+ }
44+
1745/// Automation configuration for a Kanban column.
1846/// When a card is moved to this column, the automation can trigger an agent session.
1947#[ derive( Debug , Clone , Serialize , Deserialize , Default , PartialEq ) ]
@@ -72,6 +100,24 @@ pub struct KanbanColumnAutomation {
72100 /// Required task fields before advancing
73101 #[ serde( skip_serializing_if = "Option::is_none" ) ]
74102 pub required_task_fields : Option < Vec < String > > ,
103+ /// Canonical story contract requirements
104+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
105+ pub contract_rules : Option < KanbanContractRules > ,
106+ /// Delivery-readiness requirements
107+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
108+ pub delivery_rules : Option < KanbanDeliveryRules > ,
109+ /// Required checked checklist labels before advancing
110+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
111+ pub required_checklist : Option < Vec < String > > ,
112+ /// Require an explicit approved verification verdict before advancing
113+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
114+ pub required_human_approval : Option < bool > ,
115+ /// Declarative validator command that must be represented in verification evidence
116+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
117+ pub validator_command : Option < String > ,
118+ /// Whether unmet transition gates block movement or leave an audit warning
119+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
120+ pub gate_mode : Option < KanbanTransitionGateMode > ,
75121 /// Automatically advance card on session success
76122 #[ serde( skip_serializing_if = "Option::is_none" ) ]
77123 pub auto_advance_on_success : Option < bool > ,
@@ -364,6 +410,12 @@ fn build_recommended_automation(
364410 auto_advance_on_success : Some ( auto_advance_on_success) ,
365411 required_artifacts : None ,
366412 required_task_fields : None ,
413+ contract_rules : None ,
414+ delivery_rules : None ,
415+ required_checklist : None ,
416+ required_human_approval : None ,
417+ validator_command : None ,
418+ gate_mode : None ,
367419 provider_id : None ,
368420 role : None ,
369421 specialist_id : None ,
@@ -580,6 +632,12 @@ pub fn apply_recommended_automation_to_columns(columns: Vec<KanbanColumn>) -> Ve
580632 . or ( normalized_recommended. required_artifacts . clone ( ) )
581633 } ,
582634 required_task_fields : current. required_task_fields ,
635+ contract_rules : current. contract_rules ,
636+ delivery_rules : current. delivery_rules ,
637+ required_checklist : current. required_checklist ,
638+ required_human_approval : current. required_human_approval ,
639+ validator_command : current. validator_command ,
640+ gate_mode : current. gate_mode ,
583641 auto_advance_on_success : normalized_recommended. auto_advance_on_success ,
584642 } ;
585643
0 commit comments