ricecoder_specs/
models.rs

1//! Core data models for specifications and steering
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6/// A specification document
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Spec {
9    /// Unique identifier for the spec
10    pub id: String,
11    /// Human-readable name
12    pub name: String,
13    /// Version string
14    pub version: String,
15    /// Requirements for this spec
16    pub requirements: Vec<Requirement>,
17    /// Design document (optional)
18    pub design: Option<Design>,
19    /// Implementation tasks
20    pub tasks: Vec<Task>,
21    /// Metadata about the spec
22    pub metadata: SpecMetadata,
23    /// Inheritance information (optional)
24    pub inheritance: Option<SpecInheritance>,
25}
26
27/// Metadata about a specification
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct SpecMetadata {
30    /// Author of the spec
31    pub author: Option<String>,
32    /// When the spec was created
33    pub created_at: DateTime<Utc>,
34    /// When the spec was last updated
35    pub updated_at: DateTime<Utc>,
36    /// Current phase of the spec
37    pub phase: SpecPhase,
38    /// Current status of the spec
39    pub status: SpecStatus,
40}
41
42/// Phase of specification development
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(rename_all = "lowercase")]
45pub enum SpecPhase {
46    /// Discovery phase
47    Discovery,
48    /// Requirements phase
49    Requirements,
50    /// Design phase
51    Design,
52    /// Tasks phase
53    Tasks,
54    /// Execution phase
55    Execution,
56}
57
58/// Status of a specification
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
60#[serde(rename_all = "lowercase")]
61pub enum SpecStatus {
62    /// Draft - work in progress
63    Draft,
64    /// In review - awaiting approval
65    InReview,
66    /// Approved - ready for implementation
67    Approved,
68    /// Archived - no longer active
69    Archived,
70}
71
72/// Inheritance information for hierarchical specs
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct SpecInheritance {
75    /// ID of parent spec (if any)
76    pub parent_id: Option<String>,
77    /// Precedence level (0=project, 1=feature, 2=task)
78    pub precedence_level: u32,
79    /// IDs of specs this was merged from
80    pub merged_from: Vec<String>,
81}
82
83/// A requirement with acceptance criteria
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct Requirement {
86    /// Unique identifier
87    pub id: String,
88    /// User story
89    pub user_story: String,
90    /// Acceptance criteria
91    pub acceptance_criteria: Vec<AcceptanceCriterion>,
92    /// Priority level
93    pub priority: Priority,
94}
95
96/// An acceptance criterion
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct AcceptanceCriterion {
99    /// Unique identifier
100    pub id: String,
101    /// When condition
102    pub when: String,
103    /// Then expected outcome
104    pub then: String,
105}
106
107/// Priority level
108#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
109#[serde(rename_all = "lowercase")]
110pub enum Priority {
111    /// Must have
112    Must,
113    /// Should have
114    Should,
115    /// Could have
116    Could,
117}
118
119/// Design document
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct Design {
122    /// Overview of the design
123    pub overview: String,
124    /// Architecture description
125    pub architecture: String,
126    /// Components
127    pub components: Vec<Component>,
128    /// Data models
129    pub data_models: Vec<DataModel>,
130    /// Correctness properties
131    pub correctness_properties: Vec<Property>,
132}
133
134/// A component in the design
135#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct Component {
137    /// Component name
138    pub name: String,
139    /// Component description
140    pub description: String,
141}
142
143/// A data model
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct DataModel {
146    /// Model name
147    pub name: String,
148    /// Model description
149    pub description: String,
150}
151
152/// A correctness property
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct Property {
155    /// Property identifier
156    pub id: String,
157    /// Property description
158    pub description: String,
159    /// Requirements this property validates
160    pub validates: Vec<String>,
161}
162
163/// An implementation task
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct Task {
166    /// Task identifier
167    pub id: String,
168    /// Task description
169    pub description: String,
170    /// Subtasks
171    pub subtasks: Vec<Task>,
172    /// Related requirement IDs
173    pub requirements: Vec<String>,
174    /// Task status
175    pub status: TaskStatus,
176    /// Whether this task is optional
177    pub optional: bool,
178}
179
180/// Status of a task
181#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
182#[serde(rename_all = "snake_case")]
183pub enum TaskStatus {
184    /// Not started
185    NotStarted,
186    /// In progress
187    InProgress,
188    /// Complete
189    Complete,
190}
191
192/// Steering rules and standards
193#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct Steering {
195    /// Steering rules
196    pub rules: Vec<SteeringRule>,
197    /// Standards
198    pub standards: Vec<Standard>,
199    /// Template references
200    pub templates: Vec<TemplateRef>,
201}
202
203/// A steering rule
204#[derive(Debug, Clone, Serialize, Deserialize)]
205pub struct SteeringRule {
206    /// Rule identifier
207    pub id: String,
208    /// Rule description
209    pub description: String,
210    /// Pattern to match
211    pub pattern: String,
212    /// Action to take
213    pub action: String,
214}
215
216/// A standard
217#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct Standard {
219    /// Standard identifier
220    pub id: String,
221    /// Standard description
222    pub description: String,
223}
224
225/// A template reference
226#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct TemplateRef {
228    /// Template identifier
229    pub id: String,
230    /// Template path
231    pub path: String,
232}
233
234/// A change to a spec
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct SpecChange {
237    /// Change identifier
238    pub id: String,
239    /// Spec that was changed
240    pub spec_id: String,
241    /// When the change was made
242    pub timestamp: DateTime<Utc>,
243    /// Who made the change
244    pub author: Option<String>,
245    /// Why the change was made
246    pub rationale: String,
247    /// Details of the changes
248    pub changes: Vec<ChangeDetail>,
249}
250
251/// Details of a single change
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct ChangeDetail {
254    /// Field that was changed
255    pub field: String,
256    /// Old value (if any)
257    pub old_value: Option<String>,
258    /// New value (if any)
259    pub new_value: Option<String>,
260}
261
262/// A query for specs
263#[derive(Debug, Clone, Default)]
264pub struct SpecQuery {
265    /// Query by name
266    pub name: Option<String>,
267    /// Filter by type
268    pub spec_type: Option<SpecType>,
269    /// Filter by status
270    pub status: Option<SpecStatus>,
271    /// Filter by priority
272    pub priority: Option<Priority>,
273    /// Filter by phase
274    pub phase: Option<SpecPhase>,
275    /// Custom filters
276    pub custom_filters: Vec<(String, String)>,
277}
278
279/// Type of specification
280#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
281#[serde(rename_all = "lowercase")]
282pub enum SpecType {
283    /// Feature spec
284    Feature,
285    /// Component spec
286    Component,
287    /// Task spec
288    Task,
289}
290
291/// A message in a conversation
292#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct ConversationMessage {
294    /// Message identifier
295    pub id: String,
296    /// Spec this message belongs to
297    pub spec_id: String,
298    /// Role of the message sender
299    pub role: MessageRole,
300    /// Message content
301    pub content: String,
302    /// When the message was created
303    pub timestamp: DateTime<Utc>,
304}
305
306/// Role of a conversation message
307#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
308#[serde(rename_all = "lowercase")]
309pub enum MessageRole {
310    /// User message
311    User,
312    /// Assistant message
313    Assistant,
314    /// System message
315    System,
316}
317
318/// An approval gate for phase transitions
319#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct ApprovalGate {
321    /// Phase being gated
322    pub phase: SpecPhase,
323    /// Whether this phase has been approved
324    pub approved: bool,
325    /// When the phase was approved (if at all)
326    pub approved_at: Option<DateTime<Utc>>,
327    /// Who approved the phase
328    pub approved_by: Option<String>,
329    /// Feedback on the phase
330    pub feedback: Option<String>,
331}
332
333/// A spec writing session with conversation history and approval gates
334#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct SpecWritingSession {
336    /// Session identifier
337    pub id: String,
338    /// Spec being written
339    pub spec_id: String,
340    /// Current phase of the session
341    pub phase: SpecPhase,
342    /// Conversation history
343    pub conversation_history: Vec<ConversationMessage>,
344    /// Approval gates for each phase
345    pub approval_gates: Vec<ApprovalGate>,
346    /// When the session was created
347    pub created_at: DateTime<Utc>,
348    /// When the session was last updated
349    pub updated_at: DateTime<Utc>,
350}
351
352#[cfg(test)]
353mod tests {
354    use super::*;
355
356    // ============================================================================
357    // Metadata Tests
358    // ============================================================================
359
360    #[test]
361    fn test_spec_metadata_creation() {
362        let now = Utc::now();
363        let metadata = SpecMetadata {
364            author: Some("Test Author".to_string()),
365            created_at: now,
366            updated_at: now,
367            phase: SpecPhase::Requirements,
368            status: SpecStatus::Draft,
369        };
370
371        assert_eq!(metadata.author, Some("Test Author".to_string()));
372        assert_eq!(metadata.phase, SpecPhase::Requirements);
373        assert_eq!(metadata.status, SpecStatus::Draft);
374        assert_eq!(metadata.created_at, now);
375        assert_eq!(metadata.updated_at, now);
376    }
377
378    #[test]
379    fn test_spec_metadata_no_author() {
380        let now = Utc::now();
381        let metadata = SpecMetadata {
382            author: None,
383            created_at: now,
384            updated_at: now,
385            phase: SpecPhase::Discovery,
386            status: SpecStatus::Draft,
387        };
388
389        assert!(metadata.author.is_none());
390    }
391
392    // ============================================================================
393    // Phase Serialization Tests
394    // ============================================================================
395
396    #[test]
397    fn test_spec_phase_serialization() {
398        let phases = vec![
399            SpecPhase::Discovery,
400            SpecPhase::Requirements,
401            SpecPhase::Design,
402            SpecPhase::Tasks,
403            SpecPhase::Execution,
404        ];
405
406        for phase in phases {
407            let json = serde_json::to_string(&phase).unwrap();
408            let deserialized: SpecPhase = serde_json::from_str(&json).unwrap();
409            assert_eq!(phase, deserialized);
410        }
411    }
412
413    #[test]
414    fn test_spec_status_serialization() {
415        let statuses = vec![
416            SpecStatus::Draft,
417            SpecStatus::InReview,
418            SpecStatus::Approved,
419            SpecStatus::Archived,
420        ];
421
422        for status in statuses {
423            let json = serde_json::to_string(&status).unwrap();
424            let deserialized: SpecStatus = serde_json::from_str(&json).unwrap();
425            assert_eq!(status, deserialized);
426        }
427    }
428
429    #[test]
430    fn test_priority_serialization() {
431        let priorities = vec![Priority::Must, Priority::Should, Priority::Could];
432
433        for priority in priorities {
434            let json = serde_json::to_string(&priority).unwrap();
435            let deserialized: Priority = serde_json::from_str(&json).unwrap();
436            assert_eq!(priority, deserialized);
437        }
438    }
439
440    #[test]
441    fn test_task_status_serialization() {
442        let statuses = vec![
443            TaskStatus::NotStarted,
444            TaskStatus::InProgress,
445            TaskStatus::Complete,
446        ];
447
448        for status in statuses {
449            let json = serde_json::to_string(&status).unwrap();
450            let deserialized: TaskStatus = serde_json::from_str(&json).unwrap();
451            assert_eq!(status, deserialized);
452        }
453    }
454
455    // ============================================================================
456    // Requirement Serialization Tests
457    // ============================================================================
458
459    #[test]
460    fn test_acceptance_criterion_serialization() {
461        let criterion = AcceptanceCriterion {
462            id: "AC-1.1".to_string(),
463            when: "user clicks button".to_string(),
464            then: "dialog opens".to_string(),
465        };
466
467        let json = serde_json::to_string(&criterion).unwrap();
468        let deserialized: AcceptanceCriterion = serde_json::from_str(&json).unwrap();
469
470        assert_eq!(criterion.id, deserialized.id);
471        assert_eq!(criterion.when, deserialized.when);
472        assert_eq!(criterion.then, deserialized.then);
473    }
474
475    #[test]
476    fn test_requirement_serialization() {
477        let requirement = Requirement {
478            id: "REQ-1".to_string(),
479            user_story: "As a user, I want to create tasks".to_string(),
480            acceptance_criteria: vec![
481                AcceptanceCriterion {
482                    id: "AC-1.1".to_string(),
483                    when: "user enters task".to_string(),
484                    then: "task is added".to_string(),
485                },
486                AcceptanceCriterion {
487                    id: "AC-1.2".to_string(),
488                    when: "user submits empty task".to_string(),
489                    then: "error is shown".to_string(),
490                },
491            ],
492            priority: Priority::Must,
493        };
494
495        let json = serde_json::to_string(&requirement).unwrap();
496        let deserialized: Requirement = serde_json::from_str(&json).unwrap();
497
498        assert_eq!(requirement.id, deserialized.id);
499        assert_eq!(requirement.user_story, deserialized.user_story);
500        assert_eq!(requirement.priority, deserialized.priority);
501        assert_eq!(
502            requirement.acceptance_criteria.len(),
503            deserialized.acceptance_criteria.len()
504        );
505    }
506
507    // ============================================================================
508    // Design Serialization Tests
509    // ============================================================================
510
511    #[test]
512    fn test_component_serialization() {
513        let component = Component {
514            name: "TaskManager".to_string(),
515            description: "Manages task lifecycle".to_string(),
516        };
517
518        let json = serde_json::to_string(&component).unwrap();
519        let deserialized: Component = serde_json::from_str(&json).unwrap();
520
521        assert_eq!(component.name, deserialized.name);
522        assert_eq!(component.description, deserialized.description);
523    }
524
525    #[test]
526    fn test_data_model_serialization() {
527        let model = DataModel {
528            name: "Task".to_string(),
529            description: "Represents a task in the system".to_string(),
530        };
531
532        let json = serde_json::to_string(&model).unwrap();
533        let deserialized: DataModel = serde_json::from_str(&json).unwrap();
534
535        assert_eq!(model.name, deserialized.name);
536        assert_eq!(model.description, deserialized.description);
537    }
538
539    #[test]
540    fn test_property_serialization() {
541        let property = Property {
542            id: "PROP-1".to_string(),
543            description: "For any task list, adding a task increases length by 1".to_string(),
544            validates: vec!["REQ-1.1".to_string(), "REQ-1.2".to_string()],
545        };
546
547        let json = serde_json::to_string(&property).unwrap();
548        let deserialized: Property = serde_json::from_str(&json).unwrap();
549
550        assert_eq!(property.id, deserialized.id);
551        assert_eq!(property.description, deserialized.description);
552        assert_eq!(property.validates, deserialized.validates);
553    }
554
555    #[test]
556    fn test_design_serialization() {
557        let design = Design {
558            overview: "Task management system".to_string(),
559            architecture: "Layered architecture".to_string(),
560            components: vec![Component {
561                name: "TaskManager".to_string(),
562                description: "Manages tasks".to_string(),
563            }],
564            data_models: vec![DataModel {
565                name: "Task".to_string(),
566                description: "Task entity".to_string(),
567            }],
568            correctness_properties: vec![Property {
569                id: "PROP-1".to_string(),
570                description: "Task addition property".to_string(),
571                validates: vec!["REQ-1".to_string()],
572            }],
573        };
574
575        let json = serde_json::to_string(&design).unwrap();
576        let deserialized: Design = serde_json::from_str(&json).unwrap();
577
578        assert_eq!(design.overview, deserialized.overview);
579        assert_eq!(design.architecture, deserialized.architecture);
580        assert_eq!(design.components.len(), deserialized.components.len());
581        assert_eq!(design.data_models.len(), deserialized.data_models.len());
582        assert_eq!(
583            design.correctness_properties.len(),
584            deserialized.correctness_properties.len()
585        );
586    }
587
588    // ============================================================================
589    // Task Serialization Tests
590    // ============================================================================
591
592    #[test]
593    fn test_task_serialization() {
594        let task = Task {
595            id: "1".to_string(),
596            description: "Implement task manager".to_string(),
597            subtasks: vec![Task {
598                id: "1.1".to_string(),
599                description: "Create data model".to_string(),
600                subtasks: vec![],
601                requirements: vec!["REQ-1".to_string()],
602                status: TaskStatus::NotStarted,
603                optional: false,
604            }],
605            requirements: vec!["REQ-1".to_string()],
606            status: TaskStatus::InProgress,
607            optional: false,
608        };
609
610        let json = serde_json::to_string(&task).unwrap();
611        let deserialized: Task = serde_json::from_str(&json).unwrap();
612
613        assert_eq!(task.id, deserialized.id);
614        assert_eq!(task.description, deserialized.description);
615        assert_eq!(task.status, deserialized.status);
616        assert_eq!(task.optional, deserialized.optional);
617        assert_eq!(task.subtasks.len(), deserialized.subtasks.len());
618    }
619
620    // ============================================================================
621    // Inheritance Serialization Tests
622    // ============================================================================
623
624    #[test]
625    fn test_spec_inheritance_serialization() {
626        let inheritance = SpecInheritance {
627            parent_id: Some("parent-spec".to_string()),
628            precedence_level: 1,
629            merged_from: vec!["spec-a".to_string(), "spec-b".to_string()],
630        };
631
632        let json = serde_json::to_string(&inheritance).unwrap();
633        let deserialized: SpecInheritance = serde_json::from_str(&json).unwrap();
634
635        assert_eq!(inheritance.parent_id, deserialized.parent_id);
636        assert_eq!(inheritance.precedence_level, deserialized.precedence_level);
637        assert_eq!(inheritance.merged_from, deserialized.merged_from);
638    }
639
640    #[test]
641    fn test_spec_inheritance_no_parent() {
642        let inheritance = SpecInheritance {
643            parent_id: None,
644            precedence_level: 0,
645            merged_from: vec![],
646        };
647
648        let json = serde_json::to_string(&inheritance).unwrap();
649        let deserialized: SpecInheritance = serde_json::from_str(&json).unwrap();
650
651        assert!(deserialized.parent_id.is_none());
652        assert_eq!(deserialized.precedence_level, 0);
653        assert!(deserialized.merged_from.is_empty());
654    }
655
656    #[test]
657    fn test_spec_inheritance_precedence_levels() {
658        let levels = vec![0, 1, 2];
659
660        for level in levels {
661            let inheritance = SpecInheritance {
662                parent_id: Some("parent".to_string()),
663                precedence_level: level,
664                merged_from: vec![],
665            };
666
667            let json = serde_json::to_string(&inheritance).unwrap();
668            let deserialized: SpecInheritance = serde_json::from_str(&json).unwrap();
669
670            assert_eq!(deserialized.precedence_level, level);
671        }
672    }
673
674    // ============================================================================
675    // Change Tracking Serialization Tests
676    // ============================================================================
677
678    #[test]
679    fn test_change_detail_serialization() {
680        let change = ChangeDetail {
681            field: "status".to_string(),
682            old_value: Some("Draft".to_string()),
683            new_value: Some("Approved".to_string()),
684        };
685
686        let json = serde_json::to_string(&change).unwrap();
687        let deserialized: ChangeDetail = serde_json::from_str(&json).unwrap();
688
689        assert_eq!(change.field, deserialized.field);
690        assert_eq!(change.old_value, deserialized.old_value);
691        assert_eq!(change.new_value, deserialized.new_value);
692    }
693
694    #[test]
695    fn test_change_detail_with_none_values() {
696        let change = ChangeDetail {
697            field: "new_field".to_string(),
698            old_value: None,
699            new_value: Some("value".to_string()),
700        };
701
702        let json = serde_json::to_string(&change).unwrap();
703        let deserialized: ChangeDetail = serde_json::from_str(&json).unwrap();
704
705        assert!(deserialized.old_value.is_none());
706        assert_eq!(deserialized.new_value, Some("value".to_string()));
707    }
708
709    #[test]
710    fn test_spec_change_serialization() {
711        let now = Utc::now();
712        let spec_change = SpecChange {
713            id: "change-1".to_string(),
714            spec_id: "spec-1".to_string(),
715            timestamp: now,
716            author: Some("John Doe".to_string()),
717            rationale: "Updated requirements".to_string(),
718            changes: vec![
719                ChangeDetail {
720                    field: "status".to_string(),
721                    old_value: Some("Draft".to_string()),
722                    new_value: Some("Approved".to_string()),
723                },
724                ChangeDetail {
725                    field: "phase".to_string(),
726                    old_value: Some("Requirements".to_string()),
727                    new_value: Some("Design".to_string()),
728                },
729            ],
730        };
731
732        let json = serde_json::to_string(&spec_change).unwrap();
733        let deserialized: SpecChange = serde_json::from_str(&json).unwrap();
734
735        assert_eq!(spec_change.id, deserialized.id);
736        assert_eq!(spec_change.spec_id, deserialized.spec_id);
737        assert_eq!(spec_change.author, deserialized.author);
738        assert_eq!(spec_change.rationale, deserialized.rationale);
739        assert_eq!(spec_change.changes.len(), deserialized.changes.len());
740    }
741
742    // ============================================================================
743    // Steering Serialization Tests
744    // ============================================================================
745
746    #[test]
747    fn test_steering_rule_serialization() {
748        let rule = SteeringRule {
749            id: "rule-1".to_string(),
750            description: "Use snake_case for variables".to_string(),
751            pattern: "^[a-z_]+$".to_string(),
752            action: "enforce".to_string(),
753        };
754
755        let json = serde_json::to_string(&rule).unwrap();
756        let deserialized: SteeringRule = serde_json::from_str(&json).unwrap();
757
758        assert_eq!(rule.id, deserialized.id);
759        assert_eq!(rule.description, deserialized.description);
760        assert_eq!(rule.pattern, deserialized.pattern);
761        assert_eq!(rule.action, deserialized.action);
762    }
763
764    #[test]
765    fn test_standard_serialization() {
766        let standard = Standard {
767            id: "std-1".to_string(),
768            description: "All public APIs must have tests".to_string(),
769        };
770
771        let json = serde_json::to_string(&standard).unwrap();
772        let deserialized: Standard = serde_json::from_str(&json).unwrap();
773
774        assert_eq!(standard.id, deserialized.id);
775        assert_eq!(standard.description, deserialized.description);
776    }
777
778    #[test]
779    fn test_template_ref_serialization() {
780        let template = TemplateRef {
781            id: "tpl-1".to_string(),
782            path: "templates/rust-entity.rs".to_string(),
783        };
784
785        let json = serde_json::to_string(&template).unwrap();
786        let deserialized: TemplateRef = serde_json::from_str(&json).unwrap();
787
788        assert_eq!(template.id, deserialized.id);
789        assert_eq!(template.path, deserialized.path);
790    }
791
792    #[test]
793    fn test_steering_serialization() {
794        let steering = Steering {
795            rules: vec![SteeringRule {
796                id: "rule-1".to_string(),
797                description: "Use snake_case".to_string(),
798                pattern: "^[a-z_]+$".to_string(),
799                action: "enforce".to_string(),
800            }],
801            standards: vec![Standard {
802                id: "std-1".to_string(),
803                description: "Test all public APIs".to_string(),
804            }],
805            templates: vec![TemplateRef {
806                id: "tpl-1".to_string(),
807                path: "templates/entity.rs".to_string(),
808            }],
809        };
810
811        let json = serde_json::to_string(&steering).unwrap();
812        let deserialized: Steering = serde_json::from_str(&json).unwrap();
813
814        assert_eq!(steering.rules.len(), deserialized.rules.len());
815        assert_eq!(steering.standards.len(), deserialized.standards.len());
816        assert_eq!(steering.templates.len(), deserialized.templates.len());
817    }
818
819    // ============================================================================
820    // Full Spec Serialization Tests
821    // ============================================================================
822
823    #[test]
824    fn test_spec_serialization_complete() {
825        let now = Utc::now();
826        let spec = Spec {
827            id: "feature-1".to_string(),
828            name: "Task Management".to_string(),
829            version: "1.0.0".to_string(),
830            requirements: vec![Requirement {
831                id: "REQ-1".to_string(),
832                user_story: "As a user, I want to create tasks".to_string(),
833                acceptance_criteria: vec![AcceptanceCriterion {
834                    id: "AC-1.1".to_string(),
835                    when: "user enters task".to_string(),
836                    then: "task is added".to_string(),
837                }],
838                priority: Priority::Must,
839            }],
840            design: Some(Design {
841                overview: "Task management system".to_string(),
842                architecture: "Layered".to_string(),
843                components: vec![],
844                data_models: vec![],
845                correctness_properties: vec![],
846            }),
847            tasks: vec![Task {
848                id: "1".to_string(),
849                description: "Implement task manager".to_string(),
850                subtasks: vec![],
851                requirements: vec!["REQ-1".to_string()],
852                status: TaskStatus::NotStarted,
853                optional: false,
854            }],
855            metadata: SpecMetadata {
856                author: Some("Developer".to_string()),
857                created_at: now,
858                updated_at: now,
859                phase: SpecPhase::Requirements,
860                status: SpecStatus::Draft,
861            },
862            inheritance: Some(SpecInheritance {
863                parent_id: None,
864                precedence_level: 0,
865                merged_from: vec![],
866            }),
867        };
868
869        let json = serde_json::to_string(&spec).unwrap();
870        let deserialized: Spec = serde_json::from_str(&json).unwrap();
871
872        assert_eq!(spec.id, deserialized.id);
873        assert_eq!(spec.name, deserialized.name);
874        assert_eq!(spec.version, deserialized.version);
875        assert_eq!(spec.requirements.len(), deserialized.requirements.len());
876        assert!(deserialized.design.is_some());
877        assert_eq!(spec.tasks.len(), deserialized.tasks.len());
878        assert_eq!(spec.metadata.author, deserialized.metadata.author);
879        assert!(deserialized.inheritance.is_some());
880    }
881
882    #[test]
883    fn test_spec_serialization_minimal() {
884        let now = Utc::now();
885        let spec = Spec {
886            id: "minimal".to_string(),
887            name: "Minimal Spec".to_string(),
888            version: "0.1.0".to_string(),
889            requirements: vec![],
890            design: None,
891            tasks: vec![],
892            metadata: SpecMetadata {
893                author: None,
894                created_at: now,
895                updated_at: now,
896                phase: SpecPhase::Discovery,
897                status: SpecStatus::Draft,
898            },
899            inheritance: None,
900        };
901
902        let json = serde_json::to_string(&spec).unwrap();
903        let deserialized: Spec = serde_json::from_str(&json).unwrap();
904
905        assert_eq!(spec.id, deserialized.id);
906        assert!(deserialized.design.is_none());
907        assert!(deserialized.inheritance.is_none());
908        assert!(deserialized.metadata.author.is_none());
909    }
910
911    // ============================================================================
912    // YAML Serialization Tests
913    // ============================================================================
914
915    #[test]
916    fn test_spec_yaml_serialization() {
917        let now = Utc::now();
918        let spec = Spec {
919            id: "yaml-test".to_string(),
920            name: "YAML Test Spec".to_string(),
921            version: "1.0.0".to_string(),
922            requirements: vec![],
923            design: None,
924            tasks: vec![],
925            metadata: SpecMetadata {
926                author: Some("Test Author".to_string()),
927                created_at: now,
928                updated_at: now,
929                phase: SpecPhase::Requirements,
930                status: SpecStatus::Draft,
931            },
932            inheritance: None,
933        };
934
935        let yaml = serde_yaml::to_string(&spec).unwrap();
936        let deserialized: Spec = serde_yaml::from_str(&yaml).unwrap();
937
938        assert_eq!(spec.id, deserialized.id);
939        assert_eq!(spec.name, deserialized.name);
940        assert_eq!(spec.metadata.author, deserialized.metadata.author);
941    }
942
943    #[test]
944    fn test_requirement_yaml_serialization() {
945        let requirement = Requirement {
946            id: "REQ-1".to_string(),
947            user_story: "As a user, I want to manage tasks".to_string(),
948            acceptance_criteria: vec![AcceptanceCriterion {
949                id: "AC-1.1".to_string(),
950                when: "user clicks add".to_string(),
951                then: "task is created".to_string(),
952            }],
953            priority: Priority::Must,
954        };
955
956        let yaml = serde_yaml::to_string(&requirement).unwrap();
957        let deserialized: Requirement = serde_yaml::from_str(&yaml).unwrap();
958
959        assert_eq!(requirement.id, deserialized.id);
960        assert_eq!(requirement.priority, deserialized.priority);
961    }
962
963    // ============================================================================
964    // Query Tests
965    // ============================================================================
966
967    #[test]
968    fn test_spec_query_default() {
969        let query = SpecQuery::default();
970
971        assert!(query.name.is_none());
972        assert!(query.spec_type.is_none());
973        assert!(query.status.is_none());
974        assert!(query.priority.is_none());
975        assert!(query.phase.is_none());
976        assert!(query.custom_filters.is_empty());
977    }
978
979    #[test]
980    fn test_spec_query_with_filters() {
981        let query = SpecQuery {
982            name: Some("task-management".to_string()),
983            spec_type: Some(SpecType::Feature),
984            status: Some(SpecStatus::Approved),
985            priority: Some(Priority::Must),
986            phase: Some(SpecPhase::Design),
987            custom_filters: vec![("author".to_string(), "John".to_string())],
988        };
989
990        assert_eq!(query.name, Some("task-management".to_string()));
991        assert_eq!(query.spec_type, Some(SpecType::Feature));
992        assert_eq!(query.status, Some(SpecStatus::Approved));
993        assert_eq!(query.priority, Some(Priority::Must));
994        assert_eq!(query.phase, Some(SpecPhase::Design));
995        assert_eq!(query.custom_filters.len(), 1);
996    }
997
998    // ============================================================================
999    // Approval Gate Tests
1000    // ============================================================================
1001
1002    #[test]
1003    fn test_approval_gate_creation() {
1004        let gate = ApprovalGate {
1005            phase: SpecPhase::Requirements,
1006            approved: false,
1007            approved_at: None,
1008            approved_by: None,
1009            feedback: None,
1010        };
1011
1012        assert_eq!(gate.phase, SpecPhase::Requirements);
1013        assert!(!gate.approved);
1014        assert!(gate.approved_at.is_none());
1015        assert!(gate.approved_by.is_none());
1016        assert!(gate.feedback.is_none());
1017    }
1018
1019    #[test]
1020    fn test_approval_gate_approved() {
1021        let now = Utc::now();
1022        let gate = ApprovalGate {
1023            phase: SpecPhase::Design,
1024            approved: true,
1025            approved_at: Some(now),
1026            approved_by: Some("reviewer".to_string()),
1027            feedback: Some("Looks good".to_string()),
1028        };
1029
1030        assert_eq!(gate.phase, SpecPhase::Design);
1031        assert!(gate.approved);
1032        assert_eq!(gate.approved_at, Some(now));
1033        assert_eq!(gate.approved_by, Some("reviewer".to_string()));
1034        assert_eq!(gate.feedback, Some("Looks good".to_string()));
1035    }
1036
1037    #[test]
1038    fn test_approval_gate_serialization() {
1039        let now = Utc::now();
1040        let gate = ApprovalGate {
1041            phase: SpecPhase::Tasks,
1042            approved: true,
1043            approved_at: Some(now),
1044            approved_by: Some("john".to_string()),
1045            feedback: Some("Ready to implement".to_string()),
1046        };
1047
1048        let json = serde_json::to_string(&gate).unwrap();
1049        let deserialized: ApprovalGate = serde_json::from_str(&json).unwrap();
1050
1051        assert_eq!(gate.phase, deserialized.phase);
1052        assert_eq!(gate.approved, deserialized.approved);
1053        assert_eq!(gate.approved_by, deserialized.approved_by);
1054        assert_eq!(gate.feedback, deserialized.feedback);
1055    }
1056
1057    // ============================================================================
1058    // Spec Writing Session Tests
1059    // ============================================================================
1060
1061    #[test]
1062    fn test_spec_writing_session_creation() {
1063        let now = Utc::now();
1064        let session = SpecWritingSession {
1065            id: "session-1".to_string(),
1066            spec_id: "spec-1".to_string(),
1067            phase: SpecPhase::Requirements,
1068            conversation_history: vec![],
1069            approval_gates: vec![],
1070            created_at: now,
1071            updated_at: now,
1072        };
1073
1074        assert_eq!(session.id, "session-1");
1075        assert_eq!(session.spec_id, "spec-1");
1076        assert_eq!(session.phase, SpecPhase::Requirements);
1077        assert!(session.conversation_history.is_empty());
1078        assert!(session.approval_gates.is_empty());
1079    }
1080
1081    #[test]
1082    fn test_spec_writing_session_with_messages() {
1083        let now = Utc::now();
1084        let messages = vec![
1085            ConversationMessage {
1086                id: "msg-1".to_string(),
1087                spec_id: "spec-1".to_string(),
1088                role: MessageRole::User,
1089                content: "Create a task management system".to_string(),
1090                timestamp: now,
1091            },
1092            ConversationMessage {
1093                id: "msg-2".to_string(),
1094                spec_id: "spec-1".to_string(),
1095                role: MessageRole::Assistant,
1096                content: "I'll help you create a task management system".to_string(),
1097                timestamp: now,
1098            },
1099        ];
1100
1101        let session = SpecWritingSession {
1102            id: "session-1".to_string(),
1103            spec_id: "spec-1".to_string(),
1104            phase: SpecPhase::Requirements,
1105            conversation_history: messages.clone(),
1106            approval_gates: vec![],
1107            created_at: now,
1108            updated_at: now,
1109        };
1110
1111        assert_eq!(session.conversation_history.len(), 2);
1112        assert_eq!(session.conversation_history[0].role, MessageRole::User);
1113        assert_eq!(session.conversation_history[1].role, MessageRole::Assistant);
1114    }
1115
1116    #[test]
1117    fn test_spec_writing_session_with_approval_gates() {
1118        let now = Utc::now();
1119        let gates = vec![
1120            ApprovalGate {
1121                phase: SpecPhase::Requirements,
1122                approved: true,
1123                approved_at: Some(now),
1124                approved_by: Some("reviewer".to_string()),
1125                feedback: None,
1126            },
1127            ApprovalGate {
1128                phase: SpecPhase::Design,
1129                approved: false,
1130                approved_at: None,
1131                approved_by: None,
1132                feedback: None,
1133            },
1134        ];
1135
1136        let session = SpecWritingSession {
1137            id: "session-1".to_string(),
1138            spec_id: "spec-1".to_string(),
1139            phase: SpecPhase::Design,
1140            conversation_history: vec![],
1141            approval_gates: gates.clone(),
1142            created_at: now,
1143            updated_at: now,
1144        };
1145
1146        assert_eq!(session.approval_gates.len(), 2);
1147        assert!(session.approval_gates[0].approved);
1148        assert!(!session.approval_gates[1].approved);
1149    }
1150
1151    #[test]
1152    fn test_spec_writing_session_serialization() {
1153        let now = Utc::now();
1154        let session = SpecWritingSession {
1155            id: "session-1".to_string(),
1156            spec_id: "spec-1".to_string(),
1157            phase: SpecPhase::Requirements,
1158            conversation_history: vec![ConversationMessage {
1159                id: "msg-1".to_string(),
1160                spec_id: "spec-1".to_string(),
1161                role: MessageRole::User,
1162                content: "Create a system".to_string(),
1163                timestamp: now,
1164            }],
1165            approval_gates: vec![ApprovalGate {
1166                phase: SpecPhase::Requirements,
1167                approved: false,
1168                approved_at: None,
1169                approved_by: None,
1170                feedback: None,
1171            }],
1172            created_at: now,
1173            updated_at: now,
1174        };
1175
1176        let json = serde_json::to_string(&session).unwrap();
1177        let deserialized: SpecWritingSession = serde_json::from_str(&json).unwrap();
1178
1179        assert_eq!(session.id, deserialized.id);
1180        assert_eq!(session.spec_id, deserialized.spec_id);
1181        assert_eq!(session.phase, deserialized.phase);
1182        assert_eq!(
1183            session.conversation_history.len(),
1184            deserialized.conversation_history.len()
1185        );
1186        assert_eq!(
1187            session.approval_gates.len(),
1188            deserialized.approval_gates.len()
1189        );
1190    }
1191
1192    #[test]
1193    fn test_spec_writing_session_yaml_serialization() {
1194        let now = Utc::now();
1195        let session = SpecWritingSession {
1196            id: "session-1".to_string(),
1197            spec_id: "spec-1".to_string(),
1198            phase: SpecPhase::Design,
1199            conversation_history: vec![],
1200            approval_gates: vec![],
1201            created_at: now,
1202            updated_at: now,
1203        };
1204
1205        let yaml = serde_yaml::to_string(&session).unwrap();
1206        let deserialized: SpecWritingSession = serde_yaml::from_str(&yaml).unwrap();
1207
1208        assert_eq!(session.id, deserialized.id);
1209        assert_eq!(session.spec_id, deserialized.spec_id);
1210        assert_eq!(session.phase, deserialized.phase);
1211    }
1212
1213    #[test]
1214    fn test_spec_writing_session_phase_progression() {
1215        let now = Utc::now();
1216        let phases = vec![
1217            SpecPhase::Discovery,
1218            SpecPhase::Requirements,
1219            SpecPhase::Design,
1220            SpecPhase::Tasks,
1221            SpecPhase::Execution,
1222        ];
1223
1224        for phase in phases {
1225            let session = SpecWritingSession {
1226                id: "session-1".to_string(),
1227                spec_id: "spec-1".to_string(),
1228                phase,
1229                conversation_history: vec![],
1230                approval_gates: vec![],
1231                created_at: now,
1232                updated_at: now,
1233            };
1234
1235            assert_eq!(session.phase, phase);
1236        }
1237    }
1238}