// Package domain holds the core commitment types and validation, ported from // the original Rust implementation. These are pure data types with no I/O. package domain import ( "errors" "strings" "time" "github.com/google/uuid" ) const PolicySchemaVersion = 1 type CommitmentSource string const ( SourceManual CommitmentSource = "manual" SourcePlanner CommitmentSource = "planner" SourceRecurring CommitmentSource = "recurring" SourceRecovery CommitmentSource = "recovery" SourceTemplate CommitmentSource = "template" ) type CommitmentState string const ( CommitmentDraft CommitmentState = "draft" CommitmentActive CommitmentState = "active" CommitmentPaused CommitmentState = "paused" CommitmentCompleted CommitmentState = "completed" CommitmentAbandoned CommitmentState = "abandoned" CommitmentViolated CommitmentState = "violated" ) type RuntimeState string const ( RuntimeLocked RuntimeState = "locked" RuntimePlanning RuntimeState = "planning" RuntimeActive RuntimeState = "active" RuntimeTransition RuntimeState = "transition" RuntimeReview RuntimeState = "review" RuntimeAdminOverride RuntimeState = "admin_override" ) type EnforcementLevel string const ( EnforcementObserve EnforcementLevel = "observe" EnforcementWarn EnforcementLevel = "warn" EnforcementBlock EnforcementLevel = "block" EnforcementLocked EnforcementLevel = "locked" ) // AllowedContext is carried by PolicySnapshot. Matching logic arrives in a // later milestone; M0 only stores it. type AllowedContext struct { WindowClasses []string `json:"window_classes"` WindowTitleSubstrings []string `json:"window_title_substrings"` Domains []string `json:"domains"` Repos []string `json:"repos"` Commands []string `json:"commands"` } type Commitment struct { ID string `json:"id"` CreatedAtUnixSecs int64 `json:"created_at_unix_secs"` Source CommitmentSource `json:"source"` NextAction string `json:"next_action"` SuccessCondition string `json:"success_condition"` TimeboxSecs int64 `json:"timebox_secs"` State CommitmentState `json:"state"` } type PolicySnapshot struct { ID string `json:"id"` CommitmentID string `json:"commitment_id"` SchemaVersion int `json:"schema_version"` CreatedAtUnixSecs int64 `json:"created_at_unix_secs"` RuntimeState RuntimeState `json:"runtime_state"` EnforcementLevel EnforcementLevel `json:"enforcement_level"` AllowedContext AllowedContext `json:"allowed_context"` } var ( ErrMissingNextAction = errors.New("next action is required") ErrMissingSuccessCondition = errors.New("success condition is required") ErrMissingTimebox = errors.New("timebox must be nonzero") ) // NewManual builds a validated draft commitment from user input. func NewManual(nextAction, successCondition string, timebox time.Duration) (Commitment, error) { nextAction = strings.TrimSpace(nextAction) successCondition = strings.TrimSpace(successCondition) if nextAction == "" { return Commitment{}, ErrMissingNextAction } if successCondition == "" { return Commitment{}, ErrMissingSuccessCondition } if timebox <= 0 { return Commitment{}, ErrMissingTimebox } return Commitment{ ID: "commitment-" + uuid.Must(uuid.NewV7()).String(), CreatedAtUnixSecs: time.Now().Unix(), Source: SourceManual, NextAction: nextAction, SuccessCondition: successCondition, TimeboxSecs: int64(timebox.Seconds()), State: CommitmentDraft, }, nil } // ForRuntime builds a minimal accepted policy snapshot for a commitment. func ForRuntime(commitmentID string, runtime RuntimeState, level EnforcementLevel) PolicySnapshot { return PolicySnapshot{ ID: "policy-" + uuid.Must(uuid.NewV7()).String(), CommitmentID: commitmentID, SchemaVersion: PolicySchemaVersion, CreatedAtUnixSecs: time.Now().Unix(), RuntimeState: runtime, EnforcementLevel: level, AllowedContext: AllowedContext{}, } }