### Install StatePro with Go Source: https://github.com/rendis/statepro/blob/main/docs/getting-started.md Installs the StatePro library using the Go package manager. Ensure you have Go 1.22 or newer installed. ```bash go get github.com/rendis/statepro/v3 ``` -------------------------------- ### Launch Interactive State Machine Debugger (Bash) Source: https://github.com/rendis/statepro/blob/main/docs/getting-started.md Provides commands to set up and launch the interactive debugger for state machines. It involves copying an example configuration, navigating into the directory, and executing the debugger using Go. ```bash # Copy one of the example state machines cp -r example/cli ./my-debug-session cd my-debug-session # Launch the interactive debugger go run main.go ``` -------------------------------- ### Register Custom Action in StatePro Source: https://github.com/rendis/statepro/blob/main/docs/getting-started.md Demonstrates how to register a custom action in StatePro that executes when a state transition occurs. This example logs the new state being entered. ```go // Register a custom action that runs when entering a state _ = builtin.RegisterAction("action:logStateChange", func(ctx context.Context, args instrumentation.ActionExecutorArgs) error { fmt.Printf("🔄 State changed to: %s\n", args.GetCurrentReality()) return nil }) ``` -------------------------------- ### Programmatic Bot Setup and Execution (Bash) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md This snippet demonstrates how to set up and run the programmatic bot for automated testing. It includes copying the bot example, customizing event sequences in `events.json`, and executing the automation script with `go run`. ```bash cp -r example/bot test-automation cd test-automation vim events.json go run main.go ``` -------------------------------- ### Go Application Build and Run Commands Source: https://github.com/rendis/statepro/blob/main/README.md These bash commands guide the user through initializing a Go module, adding the StatePro dependency, tidying up dependencies, and running the main Go application. This is essential for executing the StatePro example. ```bash go mod init quickstart go mod edit -require github.com/rendis/statepro/v3@v3.0.0 go mod tidy go run main.go ``` -------------------------------- ### Run Traffic Light Demo with Go Source: https://github.com/rendis/statepro/blob/main/docs/getting-started.md A Go application that loads, initializes, and runs the traffic light state machine defined in JSON. It simulates timer events and prints the current state. ```go package main import ( "context" "fmt" "log" "os" "time" "github.com/rendis/statepro/v3" "github.com/rendis/statepro/v3/builtin" "github.com/rendis/statepro/v3/instrumentation" ) func main() { // Load the state machine definition raw, err := os.ReadFile("traffic_light.json") if err != nil { log.Fatal("Error reading state machine:", err) } // Deserialize the model model, err := statepro.DeserializeQuantumMachineFromBinary(raw) if err != nil { log.Fatal("Error deserializing model:", err) } // Create the quantum machine qm, err := statepro.NewQuantumMachine(model) if err != nil { log.Fatal("Error creating quantum machine:", err) } // Initialize the machine ctx := context.Background() if err := qm.Init(ctx, nil); err != nil { log.Fatal("Error initializing machine:", err) } // Display initial state displayCurrentState(qm) // Simulate traffic light cycles for i := 0; i < 6; i++ { time.Sleep(2 * time.Second) // Simulate time passing // Send timer event timerEvent := statepro.NewEventBuilder("timer").Build() handled, err := qm.SendEvent(ctx, timerEvent) if err != nil { log.Fatal("Error sending event:", err) } if !handled { log.Println("Timer event was not handled") } displayCurrentState(qm) } } func displayCurrentState(qm instrumentation.QuantumMachine) { snapshot := qm.GetSnapshot() resume := snapshot.GetResume() fmt.Printf("🚦 Current State: %v\n", resume.ActiveUniverses) for universe, realities := range resume.ActiveUniverses { for _, reality := range realities { fmt.Printf(" Universe: %s, Reality: %s\n", universe, reality) } } fmt.Println("---") } ``` -------------------------------- ### Build StatePro Go Examples Source: https://github.com/rendis/statepro/blob/main/README.md This command compiles the example applications included in the StatePro project. Building examples is useful for demonstrating functionality and for developers to test integrations. This requires a working Go environment. ```bash go build ./example/... ``` -------------------------------- ### Interactive CLI Debugger Setup and Launch (Bash) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md This snippet shows how to set up and launch the interactive Bubble Tea CLI debugger. It involves copying an example, navigating to the session directory, modifying configuration files, and executing the debugger using `go run`. ```bash cp -r example/cli debug-session cd debug-session vim state_machine.json go run main.go ``` -------------------------------- ### StatePro Examples Execution Source: https://github.com/rendis/statepro/blob/main/README.md This section provides bash commands to run different example implementations of StatePro, including a basic state machine, an interactive Bubble Tea debugger, and an automated event playback tool. These examples showcase various features and use cases of the library. ```bash # 📊 Basic state machine execution with tracking go run example/sm # 🎮 Interactive Bubble Tea debugger go run example/cli # 🤖 Automated event playback and testing go run example/bot ``` -------------------------------- ### State Machine JSON Example - StatePro Source: https://github.com/rendis/statepro/blob/main/docs/modeling.md This JSON snippet defines a state machine for an admission process. It includes multiple universes, realities, and transitions, demonstrating how events trigger state changes and cross-universe jumps. It also showcases universal constants for logging actions. ```json { "id": "admission", "canonicalName": "admission-machine", "version": "0.1.0", "initials": ["U:admission-in-waiting-confirmation"], "universes": { "admission-in-waiting-confirmation": { "id": "admission-in-waiting-confirmation", "canonicalName": "admission-in-waiting-confirmation", "version": "0.1.0", "initial": "CREATED", "realities": { "CREATED": { "type": "transition", "always": [ { "targets": ["WAITING_CONFIRMATION"] } ] }, "WAITING_CONFIRMATION": { "type": "transition", "on": { "confirm": [ { "targets": ["CONFIRMED"] } ], "reject": [ { "targets": ["U:admission-rejected"] } ] } }, "CONFIRMED": { "type": "final", "always": [ { "targets": [ "U:admission-form-process", "U:admission-contract-process" ] } ] } } }, "admission-waiting-processes": { "id": "admission-waiting-processes", "version": "0.1.0", "realities": { "WAITING_PROCESSES": { "type": "final", "observers": [ { "src": "builtin:observer:containsAllEvents", "args": {"p1": "fill-form", "p2": "sign"} } ], "always": [ { "targets": [ "U:admission-contract-process:SIGNING_ENROLLMENT_CONTRACT" ] } ] } } } }, "universalConstants": { "entryActions": [ {"src": "builtin:action:logBasicInfo"} ], "actionsOnTransition": [ {"src": "builtin:action:logArgs"} ] } } ``` -------------------------------- ### User Onboarding State Machine Configuration Source: https://github.com/rendis/statepro/blob/main/README.md Defines a multi-step user onboarding flow with parallel tasks for email verification and account setup, triggered by an initial registration step. It showcases transitions, conditional logic, and final states. ```json { "id": "user-onboarding", "initials": ["U:registration"], "universes": { "registration": { "initial": "COLLECTING_INFO", "realities": { "COLLECTING_INFO": { "type": "transition", "on": { "submit": [{"targets": ["U:email-verification", "U:account-setup"]}] } } } }, "email-verification": { "initial": "SENDING_EMAIL", "realities": { "SENDING_EMAIL": { "type": "transition", "always": [{"targets": ["WAITING_VERIFICATION"]}], "entryActions": [{"src": "action:sendVerificationEmail"}] }, "WAITING_VERIFICATION": { "type": "transition", "on": { "verify": [{"targets": ["VERIFIED"]}], "timeout": [{"targets": ["EXPIRED"]}] } }, "VERIFIED": {"type": "final"}, "EXPIRED": {"type": "unsuccessfulFinal"} } }, "account-setup": { "realities": { "WAITING_COMPLETION": { "type": "final", "observers": [{"src": "observer:emailVerified"}] } } } } } ``` -------------------------------- ### Send Event Example (Go) Source: https://github.com/rendis/statepro/blob/main/docs/api-reference.md Example demonstrating how to create and send an event using `EventBuilder` and the quantum machine's `SendEvent` method. It shows setting event data, correlation ID, and then sending the event to the machine for processing. The result indicates if the event was handled and any potential errors. ```Go // Create an event with data event := statepro.NewEventBuilder("user.signup"). SetData(map[string]any{ "email": "user@example.com", "plan": "premium", }). SetCorrelationId("signup-123"). Build() // Send the event handled, err := qm.SendEvent(ctx, event) ``` -------------------------------- ### Register Observer for Time-Based Transitions (Go) Source: https://github.com/rendis/statepro/blob/main/docs/getting-started.md Registers an observer to control state transitions based on the current time of day. This observer allows transitions only between 6 AM and 6 PM. It takes a context and observer arguments and returns a boolean indicating if the transition is allowed and an error if one occurs. ```go // Register an observer that controls when transitions can happen _ = builtin.RegisterObserver("observer:timeOfDay", func(ctx context.Context, args instrumentation.ObserverExecutorArgs) (bool, error) { // Only allow transitions during daytime hour := time.Now().Hour() return hour >= 6 && hour <= 18, nil }) ``` -------------------------------- ### Define State Machine Admission Workflow in JSON Source: https://github.com/rendis/statepro/blob/main/README.md This JSON structure defines a simplified admission workflow for a quantum state machine in StatePro. It includes unique identifiers, starting universes, and detailed definitions for each universe, specifying states, transitions, and event handling. This serves as a foundational example for creating state machine logic. ```json { "id": "admission", // 🆔 Unique machine identifier "initials": ["U:admission-in-waiting-confirmation"], // 🚀 Starting universes "universes": { "admission-in-waiting-confirmation": { // 🌌 Universe definition "initial": "CREATED", // 📍 Starting state "realities": { "CREATED": { "type": "transition", "always": [{"targets": ["WAITING_CONFIRMATION"]}] }, "WAITING_CONFIRMATION": { // ⏳ Await decision "type": "transition", "on": { "confirm": [{"targets": ["CONFIRMED"]}], // ✅ Accept event "reject": [{"targets": ["U:admission-rejected"]}] // ❌ Reject to new universe } }, "CONFIRMED": { // 🎉 Success state "type": "final", "always": [{"targets": [ // 🔀 Split into parallel universes "U:admission-form-process", "U:admission-contract-process" ]}] } } } } } ``` -------------------------------- ### Minimal StatePro Automation Bot Usage Source: https://github.com/rendis/statepro/blob/main/docs/debugging.md Instantiate and run the StatePro Automation Bot with a minimal configuration. This example demonstrates setting up an event provider and executing the bot to simulate machine interactions and observe results. ```go qm := loadDefinition() // see modeling guide provider := func(_ *instrumentation.MachineSnapshot) (instrumentation.Event, error) { if len(events) == 0 { return nil, nil } evt := events[0] events = events[1:] return evt, nil } b, _ := bot.NewBot(qm, provider, true) _ = b.Run(context.Background(), myContext) for _, step := range b.GetHistory() { fmt.Println(step.Event.GetEventName(), step.Snapshot.GetResume()) } ``` -------------------------------- ### Load and Run State Machine in Go Source: https://github.com/rendis/statepro/blob/main/docs/modeling.md This snippet shows how to load a state machine model from a binary file, initialize the quantum machine, and send an event to the running machine in Go. It handles potential runtime errors and checks if the event was handled. ```go raw, _ := os.ReadFile("state_machine.json") model, _ := statepro.DeserializeQuantumMachineFromBinary(raw) qm, _ := statepro.NewQuantumMachine(model) ctx := context.Background() machineCtx := &AdmissionCtx{Active: true} _ = qm.Init(ctx, machineCtx) // or qm.InitWithEvent(...) handled, err := qm.SendEvent(ctx, statepro.NewEventBuilder("confirm").Build()) if err != nil { // handle runtime errors from actions/conditions } if !handled { // the event did not match any active reality } ``` -------------------------------- ### Define Traffic Light State Machine in JSON Source: https://github.com/rendis/statepro/blob/main/docs/getting-started.md A JSON definition for a simple traffic light state machine. It includes states (RED, GREEN, YELLOW), transitions triggered by a 'timer' event, and metadata like duration and color for each state. ```json { "id": "traffic-light", "canonicalName": "simple-traffic-light", "version": "1.0.0", "initials": ["U:main-traffic-flow"], "universes": { "main-traffic-flow": { "id": "main-traffic-flow", "initial": "RED", "realities": { "RED": { "type": "transition", "on": { "timer": [{"targets": ["GREEN"]}] }, "metadata": { "duration": 30, "color": "#FF0000" } }, "GREEN": { "type": "transition", "on": { "timer": [{"targets": ["YELLOW"]}] }, "metadata": { "duration": 45, "color": "#00FF00" } }, "YELLOW": { "type": "transition", "on": { "timer": [{"targets": ["RED"]}] }, "metadata": { "duration": 5, "color": "#FFFF00" } } } } } } ``` -------------------------------- ### Code Comments for Complex Logic in Go Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Illustrates documenting complex business logic within code executors using comments. This example registers an action for processing orders and includes details about validation and external integrations. ```go // RegisterOrderProcessingActions sets up all actions needed for order processing. // This includes payment validation, inventory checks, and shipping coordination. func RegisterOrderProcessingActions() { // Validates payment information and processes charge // Integrates with PaymentGateway v3 API // Timeout: 30 seconds, Retries: 3 attempts builtin.RegisterAction("action:processPayment", func(ctx context.Context, args instrumentation.ActionExecutorArgs) error { data := args.GetEventData() // Extract payment details amount, ok := data["amount"].(float64) if !ok { return fmt.Errorf("invalid amount in payment data") } // Business rule: Amounts over $10,000 require manual approval if amount > 10000 { return triggerManualApproval(data) } return processPaymentNormally(data) }) } ``` -------------------------------- ### StatePro JSON: Required Fields and Reality Types Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md Provides examples of valid JSON structures for StatePro state machine definitions, focusing on essential fields like 'id', 'initials', and 'universes', as well as correct 'type' values for realities. ```json { "id": "required-field", "initials": ["U:universe-name"], "universes": { "universe-name": { "id": "universe-name", "realities": { "STATE_NAME": { "type": "transition" } } } } } { "SOME_STATE": { "type": "transition", // ✅ Valid: "transition", "final", "unsuccessfulFinal" "on": { "event": [{"targets": ["NEXT_STATE"]}] } } } ``` -------------------------------- ### StatePro Structured Event Data with Go Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Demonstrates how to structure event payloads consistently in StatePro using Go. This example defines a `EventData` struct and shows how to populate it when building an event, ensuring uniformity across event data. ```go // ✅ Good: Consistent structure type EventData struct { UserID string `json:"userId"` CorrelationID string `json:"correlationId"` Timestamp time.Time `json:"timestamp"` Payload map[string]interface{} `json:"payload"` } event := statepro.NewEventBuilder("order.create"). SetData(map[string]any{ "userId": "user-123", "correlationId": "req-456", "timestamp": time.Now(), "payload": map[string]any{ "productId": "prod-789", "quantity": 2, "price": 29.99, }, }). SetCorrelationId("req-456"). Build() ``` -------------------------------- ### State Machine Metadata in JSON Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Provides an example of JSON structure for documenting state machines at multiple levels, including general metadata and universe-specific details. ```json { "id": "order-fulfillment", "metadata": { "description": "Handles order processing from confirmation to delivery", "version": "2.1.0", "author": "fulfillment-team", "documentation": "https://wiki.company.com/order-fulfillment" }, "universes": { "payment-processing": { "metadata": { "description": "Processes payments via external gateway", "timeout": "30 seconds", "retryPolicy": "3 attempts with exponential backoff" } } } } ``` -------------------------------- ### Run StatePro Go Tests Source: https://github.com/rendis/statepro/blob/main/README.md This command executes all tests within the StatePro project using Go's built-in testing framework. It's crucial for ensuring the integrity and correctness of the codebase. Ensure Go is installed and the project dependencies are managed correctly. ```bash go test ./... ``` -------------------------------- ### Run StatePro CLI Debugger Sample Source: https://github.com/rendis/statepro/blob/main/docs/debugging.md Execute the sample CLI debugger for StatePro. This command initiates the interactive TUI debugger, which loads definitions, events, and snapshots for exploration. It's the simplest way to start using the debugger. ```bash go run ./example/cli ``` -------------------------------- ### Efficient Observer Design in Go Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Provides examples in Go for designing efficient observers in StatePro. It contrasts a good practice of using fast, simple conditions with a bad practice of performing expensive database queries within observers, highlighting performance implications. ```go // ✅ Good: Fast, simple conditions builtin.RegisterObserver("observer:businessHours", func(ctx context.Context, args instrumentation.ObserverExecutorArgs) (bool, error) { hour := time.Now().Hour() return hour >= 9 && hour <= 17, nil }) // ❌ Avoid: Expensive operations in observers builtin.RegisterObserver("observer:userExists", func(ctx context.Context, args instrumentation.ObserverExecutorArgs) (bool, error) { userID := args.GetEventData()["userId"].(string) // Don't do expensive DB queries in observers user, err := database.FindUser(userID) // Slow! return user != nil, err }) ``` -------------------------------- ### Async Background Job Invocation (Go) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md This Go code registers an invoke function named 'invoke:backgroundJob' that executes a background task. It starts a goroutine to perform work (simulated by `time.Sleep`) and then sends a 'jobComplete' event using `qm.SendEvent`. Ensure `statepro` and `time` packages are imported. ```go builtin.RegisterInvoke("invoke:backgroundJob", func(ctx context.Context, args instrumentation.InvokeExecutorArgs) error { go func() { // Do background work time.Sleep(5 * time.Second) // Send completion event event := statepro.NewEventBuilder("jobComplete").Build() qm.SendEvent(context.Background(), event) }() return nil }) ``` -------------------------------- ### Debugging StatePro Observer Conditions (Go) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md Illustrates how to debug observer conditions in StatePro by registering a custom observer and adding logging. This helps in verifying if guard conditions are correctly evaluated and why a transition might be blocked. ```go // Check if observers are rejecting the transition builtin.RegisterObserver("observer:businessHours", func(ctx context.Context, args instrumentation.ObserverExecutorArgs) (bool, error) { // Log the evaluation for debugging result := isBusinessHours() log.Printf("Business hours check: %v", result) return result, nil }) ``` -------------------------------- ### Validating StatePro JSON Model Syntax (Bash) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md Shows how to use `jq` in Bash to validate the syntax of a StatePro JSON state machine definition. This is a common first step to catch errors before initializing the machine. ```bash # Use a JSON validator to check syntax cat state_machine.json | jq . ``` -------------------------------- ### Handling Errors in StatePro Actions (Go) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md Shows a robust implementation of a StatePro action that includes error handling for missing or invalid data within event payloads, preventing runtime crashes and providing informative error messages. ```go // Handle potential nil pointer errors builtin.RegisterAction("action:updateUser", func(ctx context.Context, args instrumentation.ActionExecutorArgs) error { data := args.GetEventData() userID, ok := data["userId"].(string) if !ok || userID == "" { return fmt.Errorf("missing or invalid userId in event data") } // Continue with processing... return nil }) ``` -------------------------------- ### Manage Quantum Machine Snapshots Source: https://github.com/rendis/statepro/blob/main/docs/api-reference.md Provides functionality to load a machine state from a snapshot and to get the current machine state as a snapshot. Loading a snapshot restores the machine's state, while getting a snapshot captures the current state. ```go snapshot := qm.GetSnapshot() // ... later or in another process ... err := qm.LoadSnapshot(snapshot, machineContext) ``` -------------------------------- ### StatePro JSON: Initial Universes Configuration Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md Illustrates how the 'initials' field in the StatePro JSON model can lead to multiple active universes if not configured carefully. This is a key point for understanding and preventing superposition issues. ```json { "initials": [ "U:universe1", // Starts universe1 "U:universe2" // Also starts universe2 - both will be active! ] } ``` -------------------------------- ### Debugging StatePro Actions with Logging (Go) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md Demonstrates adding detailed logging within custom StatePro actions using `builtin.RegisterAction`. This helps in tracing execution flow and identifying issues during event processing, especially when actions throw errors. ```go // Add logging to your custom executors builtin.RegisterAction("action:processData", func(ctx context.Context, args instrumentation.ActionExecutorArgs) error { log.Printf("Executing processData action with event: %+v", args.GetEventData()) err := doProcessing() if err != nil { log.Printf("Processing failed: %v", err) return err } return nil }) ``` -------------------------------- ### Authorization Checks in Go Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Implements authorization checks within observers to determine user permissions. This example checks if a user can modify a specific order. ```go builtin.RegisterObserver("observer:userCanModifyOrder", func(ctx context.Context, args instrumentation.ObserverExecutorArgs) (bool, error) { data := args.GetEventData() userID := data["userId"].(string) orderID := data["orderId"].(string) // Check if user owns the order order, err := orderService.GetOrder(orderID) if err != nil { return false, err } return order.UserID == userID, nil }) ``` -------------------------------- ### Implement Structured Logging in Go Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Details how to implement structured logging for custom executors in the statepro project using Go's slog package. This ensures consistent logging of state transitions and action execution details. The example shows a logger struct and its usage within an action. ```go type MachineLogger struct { logger *slog.Logger } func (ml *MachineLogger) LogTransition(universe, from, to, event string) { ml.logger.Info("state transition", "universe", universe, "from", from, "to", to, "event", event, ) } // Use in actions builtin.RegisterAction("action:processPayment", func(ctx context.Context, args instrumentation.ActionExecutorArgs) error { logger.Info("processing payment", "universe", args.GetCurrentUniverse(), "reality", args.GetCurrentReality(), "event", args.GetEventName(), "correlationId", args.GetCorrelationId(), ) // Process payment... return nil }) ``` -------------------------------- ### Custom Debug Logging Action (Go) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md This Go code registers a custom action named 'action:debug' that logs detailed information about the current state, event data, and machine context. It utilizes `log.Printf` for output and `instrumentation.ActionExecutorArgs` for accessing execution context. Ensure the `context` and `log` packages are imported. ```go builtin.RegisterAction("action:debug", func(ctx context.Context, args instrumentation.ActionExecutorArgs) error { log.Printf("=== DEBUG ACTION ===") log.Printf("Current Universe: %s", args.GetCurrentUniverse()) log.Printf("Current Reality: %s", args.GetCurrentReality()) log.Printf("Event Name: %s", args.GetEventName()) log.Printf("Event Data: %+v", args.GetEventData()) log.Printf("Machine Context: %+v", args.GetContext()) log.Printf("===================") return nil }) ``` -------------------------------- ### Minimizing Event Payload Size in StatePro (Go) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md Contrasts inefficient and efficient ways to set data in StatePro events using `SetData`. It advises against including large payloads directly and suggests using identifiers or references instead to optimize memory usage. ```go // ❌ Avoid large payloads event := statepro.NewEventBuilder("process"). SetData(map[string]any{ "largeFile": fileContents, // Could be MBs }). Build() // ✅ Use references instead event := statepro.NewEventBuilder("process"). SetData(map[string]any{ "fileId": "abc123", }). Build() ``` -------------------------------- ### Go State Machine Execution with StatePro Source: https://github.com/rendis/statepro/blob/main/README.md This Go program demonstrates how to initialize a quantum machine from a workflow definition, handle user context, send events, and retrieve the current state snapshot. It requires the 'statepro' library and a 'workflow.json' file. ```go package main import ( "context" "log" "os" "github.com/rendis/statepro/v3" ) func main() { // Load the workflow definition raw, err := os.ReadFile("workflow.json") if err != nil { log.Fatal("Error reading workflow:", err) } // Parse the JSON into a model model, err := statepro.DeserializeQuantumMachineFromBinary(raw) if err != nil { log.Fatal("Error parsing model:", err) } // Create the quantum machine qm, err := statepro.NewQuantumMachine(model) if err != nil { log.Fatal("Error creating machine:", err) } // Initialize with context (can be any Go value) ctx := context.Background() userCtx := map[string]any{"userId": "user123"} if err := qm.Init(ctx, userCtx); err != nil { log.Fatal("Error initializing:", err) } // Send an event event := statepro.NewEventBuilder("submit"). SetData(map[string]any{"email": "user@example.com"}). Build() handled, err := qm.SendEvent(ctx, event) if err != nil { log.Fatal("Error sending event:", err) } if handled { log.Println("✅ Event processed successfully") } else { log.Println("⚠️ Event was ignored (no matching transitions)") } // Check current state snapshot := qm.GetSnapshot() resume := snapshot.GetResume() log.Printf("Active workflows: %v", resume.ActiveUniverses) } ``` -------------------------------- ### Positioning State Machine Using Canonical Name and Initial State Source: https://context7.com/rendis/statepro/llms.txt This Go code demonstrates positioning a state machine using its canonical name for a specific universe and state ('U:email-verification', 'VERIFIED'), optionally executing the full entry flow. It also shows how to position a machine on the initial state of another universe ('U:account-setup') without specifying a state. These methods are useful for setting up complex test scenarios. ```go package main import ( "context" "log" "testing" "github.com/rendis/statepro/v3" "github.com/rendis/statepro/v3/instrumentation" ) func TestPositionByCanonicalName(t *testing.T) { // Load model raw, _ := os.ReadFile("signup_workflow.json") model, _ := statepro.DeserializeQuantumMachineFromBinary(raw) qm, _ := statepro.NewQuantumMachine(model) ctx := context.Background() machineCtx := map[string]any{"testMode": true} // Position using canonical name and execute full entry flow err := qm.PositionMachineByCanonicalName(ctx, machineCtx, "U:email-verification", "VERIFIED", true) if err != nil { t.Fatalf("Failed to position by canonical name: %v", err) } // Position on initial state of a universe err = qm.PositionMachineOnInitialByCanonicalName(ctx, machineCtx, "U:account-setup", true) if err != nil { t.Fatalf("Failed to position on initial: %v", err) } log.Println("Successfully positioned machine for testing") } ``` -------------------------------- ### Initialize Quantum Machine in Go Source: https://context7.com/rendis/statepro/llms.txt Creates and initializes a quantum machine from a JSON model definition in Go. It loads the model from a file, deserializes it, creates the machine, and initializes it with a context and machine-specific data. Dependencies include the 'context', 'log', 'os', and 'github.com/rendis/statepro/v3' packages. ```go package main import ( "context" "log" "os" "github.com/rendis/statepro/v3" ) func main() { // Load JSON definition raw, err := os.ReadFile("workflow.json") if err != nil { log.Fatal("Error reading workflow:", err) } // Deserialize the model model, err := statepro.DeserializeQuantumMachineFromBinary(raw) if err != nil { log.Fatal("Error parsing model:", err) } // Create quantum machine qm, err := statepro.NewQuantumMachine(model) if err != nil { log.Fatal("Error creating machine:", err) } // Initialize with context ctx := context.Background() machineCtx := map[string]any{ "userId": "user123", "sessionId": "sess456", } if err := qm.Init(ctx, machineCtx); err != nil { log.Fatal("Error initializing:", err) } log.Println("Quantum machine initialized successfully") } ``` -------------------------------- ### GET /api/state Source: https://context7.com/rendis/statepro/llms.txt Retrieves the current state of the StatePro Quantum Machine, including active, finalized, and superposition universes, along with tracking information. ```APIDOC ## GET /api/state ### Description This endpoint provides a snapshot of the current state of the StatePro Quantum Machine, offering insights into all active, finalized, and in-progress universes. ### Method GET ### Endpoint /api/state ### Parameters None ### Request Example ```json (No request body for GET requests) ``` ### Response #### Success Response (200) - **activeUniverses** (object) - A map of universe names to their current reality (state). - **finalizedUniverses** (object) - A map of universe names to their final reality. - **superpositionUniverses** (object) - A map of universe names currently in superposition. - **tracking** (object) - Information about the machine's tracking status. #### Response Example ```json { "activeUniverses": { "shipment": "DELIVERED" }, "finalizedUniverses": {}, "superpositionUniverses": {}, "tracking": { "enabled": true, "metrics": [] } } ``` ``` -------------------------------- ### JSON Workflow Definition for User Signup Source: https://github.com/rendis/statepro/blob/main/README.md This JSON defines a simple user signup workflow for StatePro. It includes initial states, transitions triggered by events like 'submit' and 'verify', and final states. ```json { "id": "user-signup", "initials": ["U:signup-process"], "universes": { "signup-process": { "initial": "COLLECTING_INFO", "realities": { "COLLECTING_INFO": { "type": "transition", "on": { "submit": [{"targets": ["VERIFYING_EMAIL"]}] } }, "VERIFYING_EMAIL": { "type": "transition", "on": { "verify": [{"targets": ["COMPLETED"]}], "timeout": [{"targets": ["EXPIRED"]}] } }, "COMPLETED": { "type": "final" }, "EXPIRED": { "type": "unsuccessfulFinal" } } } } } ``` -------------------------------- ### Async Operations Trigger (JSON) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md This JSON defines a state transition that triggers an asynchronous background job. The 'PROCESSING' state uses an 'always' transition to move to 'WAITING_CALLBACK', invoking the 'invoke:backgroundJob' executor. ```json { "PROCESSING": { "type": "transition", "always": [{ "targets": ["WAITING_CALLBACK"], "invokes": [{"executor": "invoke:backgroundJob"}] }] } } ``` -------------------------------- ### Integration Test State Machine Flow in Go Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Shows how to perform integration testing on a state machine's flow using the bot pattern in Go. This involves deserializing a state machine model, initializing it, sending a sequence of events, and verifying the final state. Requires the statepro library and JSON files for state machine definitions. ```go func TestUserOnboardingFlow(t *testing.T) { // Load test state machine model, err := statepro.DeserializeQuantumMachineFromFile("test_onboarding.json") require.NoError(t, err) qm, err := statepro.NewQuantumMachine(model) require.NoError(t, err) err = qm.Init(context.Background(), nil) require.NoError(t, err) // Test complete flow events := []string{"user.register", "email.verify", "profile.complete"} for _, eventName := range events { event := statepro.NewEventBuilder(eventName).Build() handled, err := qm.SendEvent(context.Background(), event) assert.NoError(t, err) assert.True(t, handled, "Event %s should be handled", eventName) } // Verify final state snapshot := qm.GetSnapshot() resume := snapshot.GetResume() // Should end in onboarding-complete universe assert.Contains(t, resume.ActiveUniverses, "onboarding-complete") } ``` -------------------------------- ### Create Quantum Machine - Go Source: https://github.com/rendis/statepro/blob/main/docs/api-reference.md Creates a new executable quantum machine from a theoretical model. It accepts the model and optional configuration parameters. Returns the quantum machine instance and an error if initialization fails. ```Go func NewQuantumMachine(model theoretical.QuantumMachineModel, opts ...QuantumMachineOption) (instrumentation.QuantumMachine, error) ``` ```Go qm, err := statepro.NewQuantumMachine(model) if err != nil { log.Fatal("Failed to create quantum machine:", err) } ``` -------------------------------- ### Capture and Restore Machine Snapshots in Go Source: https://context7.com/rendis/statepro/llms.txt Demonstrates capturing the current state of a quantum machine, serializing it to JSON, saving it to a file, and later restoring the machine from the saved snapshot. This is useful for persistence, recovery, or testing. ```go package main import ( "context" "encoding/json" "log" "os" "github.com/rendis/statepro/v3" "github.com/rendis/statepro/v3/instrumentation" ) func saveAndRestoreMachine(qm instrumentation.QuantumMachine) error { ctx := context.Background() // Process some events event := statepro.NewEventBuilder("confirm").Build() if _, err := qm.SendEvent(ctx, event); err != nil { return err } // Capture current state snapshot := qm.GetSnapshot() // Inspect active universes resume := snapshot.GetResume() log.Printf("Active universes: %v", resume.ActiveUniverses) log.Printf("Finalized universes: %v", resume.FinalizedUniverses) log.Printf("Superposition universes: %v", resume.SuperpositionUniverses) // Serialize snapshot to JSON snapshotJSON, err := snapshot.ToJson() if err != nil { return fmt.Errorf("snapshot serialization failed: %w", err) } // Save to file if err := os.WriteFile("snapshot.json", []byte(snapshotJSON), 0644); err != nil { return err } // Later: restore from snapshot savedData, err := os.ReadFile("snapshot.json") if err != nil { return err } var restoredSnapshot instrumentation.MachineSnapshot if err := json.Unmarshal(savedData, &restoredSnapshot); err != nil { return err } // Load snapshot into machine machineCtx := map[string]any{"restored": true} if err := qm.LoadSnapshot(&restoredSnapshot, machineCtx); err != nil { return fmt.Errorf("snapshot restoration failed: %w", err) } log.Println("Machine state restored successfully") return nil } ``` -------------------------------- ### Event-Driven Microservices Coordination State Machine Configuration Source: https://github.com/rendis/statepro/blob/main/README.md Coordinates multiple microservices through event-driven communication. This state machine defines a request handling process that fans out to user and notification services, waiting for specific events as confirmation. ```json { "id": "service-coordination", "initials": ["U:request-handler"], "universes": { "request-handler": { "initial": "PROCESSING", "realities": { "PROCESSING": { "type": "transition", "always": [{"targets": ["U:user-service", "U:notification-service"]}] } } }, "user-service": { "realities": { "WAITING_RESPONSE": { "type": "final", "observers": [{"src": "observer:userEventReceived", "args": {"expectedEvent": "user.updated"}}] } } }, "notification-service": { "realities": { "WAITING_RESPONSE": { "type": "final", "observers": [{"src": "observer:notificationEventReceived", "args": {"expectedEvent": "notification.sent"}}] } } } } } ``` -------------------------------- ### Correcting Event Name Mismatch in StatePro (Go) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md Demonstrates how to correctly send events to a StatePro state machine by ensuring the event name matches the JSON definition, highlighting case sensitivity. This is crucial for events to be recognized and handled. ```go // ❌ Wrong - case sensitive event := statepro.NewEventBuilder("Confirm").Build() // ✅ Correct - matches JSON definition event := statepro.NewEventBuilder("confirm").Build() ``` -------------------------------- ### Initialize Quantum Machine Source: https://github.com/rendis/statepro/blob/main/docs/api-reference.md Initializes the quantum machine. It can be done with optional context or with a custom event to propagate during the initialization process. Returns an error if initialization fails. ```go err := qm.Init(ctx, map[string]any{"userId": "user123"}) if err != nil { log.Fatal("Initialization failed:", err) } ``` ```go initEvent := statepro.NewEventBuilder("init"). SetData(map[string]any{"source": "migration"}). Build() err := qm.InitWithEvent(ctx, machineContext, initEvent) ``` -------------------------------- ### StatePro Event and Executor Naming Conventions (Go) Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Shows the recommended patterns for naming events and custom executors in StatePro using Go. Events follow a 'domain.action' pattern, while custom executors use a 'type:descriptiveName' format for clarity and organization. ```go // Use domain.action pattern event := statepro.NewEventBuilder("payment.process").Build() event := statepro.NewEventBuilder("user.signup").Build() event := statepro.NewEventBuilder("order.cancel").Build() ``` ```go // Use type:descriptiveName pattern builtin.RegisterAction("action:sendWelcomeEmail", handler) builtin.RegisterObserver("observer:businessHoursOnly", guard) builtin.RegisterCondition("condition:hasPremiumAccess", checker) ``` -------------------------------- ### Unit Test Custom Executor in Go Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Demonstrates how to unit test custom actions in Go for the statepro project. It involves mocking dependencies, registering the action with a test-specific name, and asserting the logic's correctness. No external dependencies beyond standard Go testing libraries are required. ```go func TestProcessOrderAction(t *testing.T) { // Mock dependencies orderService := &MockOrderService{} // Register with test-specific name builtin.RegisterAction("test:processOrder", func(ctx context.Context, args instrumentation.ActionExecutorArgs) error { return processOrder(orderService, args.GetEventData()) }) // Test the action logic eventData := map[string]any{ "orderId": "order-123", "userId": "user-456", } err := processOrder(orderService, eventData) assert.NoError(t, err) assert.True(t, orderService.ProcessOrderCalled) } ``` -------------------------------- ### StatePro Event Versioning Strategies (Go) Source: https://github.com/rendis/statepro/blob/main/docs/best-practices.md Illustrates two common strategies for versioning events in StatePro using Go: embedding the version number directly in the event name (e.g., 'order.create.v2') or including a 'version' field within the event data payload. ```go // Version in event names event := statepro.NewEventBuilder("order.create.v2").Build() ``` ```go // Or version in event data event := statepro.NewEventBuilder("order.create"). SetData(map[string]any{ "version": "2.0", "userId": "123", // ... other fields }). Build() ``` -------------------------------- ### Manage StatePro Go Module Dependencies Source: https://github.com/rendis/statepro/blob/main/README.md This command synchronizes the `go.mod` and `go.sum` files, ensuring all project dependencies are correctly listed and downloaded. It's a standard Go operation for maintaining module integrity. Run this command after adding or removing dependencies. ```bash go mod tidy ``` -------------------------------- ### Register Custom Observer Go Example Source: https://github.com/rendis/statepro/blob/main/docs/instrumentation.md Demonstrates how to register a custom observer named 'custom:observer:requiresCounter' using the builtin.RegisterObserver function. The observer checks if at least two 'confirm' events have occurred for a given reality. Dependencies include 'context', 'instrumentation', and 'builtin'. ```go func init() { _ = builtin.RegisterObserver("custom:observer:requiresCounter", requireCounter) } func requireCounter(ctx context.Context, args instrumentation.ObserverExecutorArgs) (bool, error) { stats := args.GetAccumulatorStatistics() if stats == nil { return false, nil } events := stats.GetAllRealityEvents(args.GetRealityName()) return len(events["confirm"]) >= 2, nil } ``` -------------------------------- ### Go: Handle Errors from NewQuantumMachine and SendEvent Source: https://github.com/rendis/statepro/blob/main/docs/api-reference.md Demonstrates essential error handling when initializing a QuantumMachine and sending events. It covers checking for errors during machine creation due to model validation and during event processing. ```go qm, err := statepro.NewQuantumMachine(model) if err != nil { // Handle model validation errors log.Fatal("Model validation failed:", err) } handled, err := qm.SendEvent(ctx, event) if err != nil { // Handle event processing errors log.Error("Event processing failed:", err) } ``` -------------------------------- ### Error Handling State Transitions (JSON) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md This JSON defines state transitions for error handling. It includes states like 'PROCESSING', 'COMPLETED', and 'FAILED'. The 'PROCESSING' state transitions to 'COMPLETED' on success and 'FAILED' on error. The 'FAILED' state is marked as 'unsuccessfulFinal' with metadata indicating a 'retry' strategy. ```json { "PROCESSING": { "type": "transition", "on": { "success": [{"targets": ["COMPLETED"]}], "error": [{"targets": ["FAILED"]}] } }, "COMPLETED": { "type": "final" }, "FAILED": { "type": "unsuccessfulFinal", "metadata": { "errorHandling": "retry" } } } ``` -------------------------------- ### Conditional Transition Observer (Go) Source: https://github.com/rendis/statepro/blob/main/docs/troubleshooting.md This Go code registers an observer named 'observer:checkUserRole' that checks if the 'userRole' from event data is 'admin'. It returns `true` if the role matches, enabling conditional transitions. This requires the `fmt` package for error formatting and `instrumentation.ObserverExecutorArgs` for accessing event data. ```go builtin.RegisterObserver("observer:checkUserRole", func(ctx context.Context, args instrumentation.ObserverExecutorArgs) (bool, error) { data := args.GetEventData() role, ok := data["userRole"].(string) if !ok { return false, fmt.Errorf("userRole missing from event") } return role == "admin", nil }) ```