Skip to content

Conversation

@johnnyt
Copy link
Member

@johnnyt johnnyt commented Aug 30, 2025

Introduces a comprehensive GenServer-based StateMachine system with production-ready examples and enhanced developer experience.

Key Changes

StateMachine GenServer Infrastructure:

  • Adds Statifier.StateMachine macro with use syntax for easy state machine creation
  • Implements callback system with handle_state_enter/3 and handle_transition/4 hooks
  • Provides DynamicSupervisor for managing multiple state machine processes
  • Adds top-level API with start_link/2 and configuration options

Examples Umbrella Application:

  • Creates new examples/ umbrella app with production-ready patterns
  • Migrates approval workflow example with comprehensive test coverage
  • Adds detailed documentation and API references
  • Implements business logic callbacks and logging integration

Enhanced Developer Experience:

  • Improves logging with trace/debug filtering and structured output
  • Adds comprehensive test suites demonstrating best practices
  • Includes boundary value testing and data persistence validation

Technical Improvements:

  • Fixes _event.data assignment support for SCXML expressions
  • Resolves deprecated :warn log level warnings
  • Applies consistent code formatting and linting
  • Adds type specifications and documentation coverage

The examples now serve as production-ready templates for building workflow engines with Statifier, showcasing advanced SCXML features in real Elixir applications.

@codecov
Copy link

codecov bot commented Aug 30, 2025

Codecov Report

❌ Patch coverage is 91.78082% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
lib/statifier/state_machine.ex 91.52% 5 Missing ⚠️
lib/statifier/logging/elixir_logger_adapter.ex 0.00% 1 Missing ⚠️
Files with missing lines Coverage Δ
lib/statifier.ex 100.00% <100.00%> (ø)
lib/statifier/interpreter.ex 91.35% <100.00%> (+0.04%) ⬆️
lib/statifier/logging/adapter.ex 100.00% <ø> (ø)
lib/statifier/logging/log_manager.ex 83.87% <ø> (ø)
lib/statifier/supervisor.ex 100.00% <100.00%> (ø)
lib/statifier/logging/elixir_logger_adapter.ex 75.00% <0.00%> (-5.00%) ⬇️
lib/statifier/state_machine.ex 91.52% <91.52%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

johnnyt and others added 4 commits September 4, 2025 04:26
- **Statifier.StateMachine**: GenServer wrapper around StateChart for async processing
  - Supports SCXML file paths and XML string initialization
  - Async event processing with send_event/2-3
  - Query methods: active_states/1, get_state_chart/1
  - Proper error handling with descriptive error tuples via {:shutdown, reason}

- **Statifier.send/2-3**: Async event sending to StateMachine processes
- **Statifier.send_sync/2-3**: Sync event sending to StateChart (delegates to Interpreter)

- File and XML string initialization with proper validation
- Async event processing with GenServer cast
- Clean separation between sync (StateChart) and async (StateMachine) workflows
- Comprehensive test coverage (9 new tests)
- Descriptive error handling preserving full error context

- All 867 tests pass
- No credo issues
- No dialyzer warnings
- Full type specs and documentation

Phase 1 establishes the foundation for async state chart processing
while maintaining compatibility with existing sync API.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- **Statifier.Supervisor**: DynamicSupervisor for StateMachine process lifecycle
  - start_child/2-3: Create supervised StateMachine processes
  - terminate_child/2: Gracefully terminate StateMachine processes
  - which_children/1: List all supervised processes
  - count_children/1: Get process counts and statistics
  - Automatic restart on crashes with :one_for_one strategy

- **Dual initialization modes**: Handles both direct and supervisor-based startup
  - Direct: `StateMachine.start_link(init_arg, opts)`
  - Supervised: Uses `{init_arg, opts}` tuple format
- **Named process support**: Full GenServer name registration through supervisor
- **Proper child specifications**: Custom child specs with permanent restart strategy

- **OTP-compliant supervision**: DynamicSupervisor with configurable strategies
- **Process isolation**: Individual StateMachine crashes don't affect others
- **Cluster-ready architecture**: Foundation for future distributed deployment
- **Comprehensive testing**: 11 new tests covering all supervision scenarios
- **Automatic restart behavior**: Crashed processes restart with same configuration

- All 878 tests pass (+11 new tests)
- No credo issues
- No dialyzer warnings
- Full type specs and documentation

```elixir
{:ok, supervisor} = Statifier.Supervisor.start_link()

{:ok, pid} = Statifier.Supervisor.start_child(supervisor, "machine.xml")
{:ok, named_pid} = Statifier.Supervisor.start_child(supervisor, xml, name: :my_machine)

children = Statifier.Supervisor.which_children(supervisor)
%{active: count} = Statifier.Supervisor.count_children(supervisor)
:ok = Statifier.Supervisor.terminate_child(supervisor, pid)
```

Phase 2 establishes proper OTP supervision for async StateMachine processes,
enabling production-ready process management and fault tolerance.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Create Statifier.StateMachineBehaviour defining optional callbacks
- Add __using__ macro to Statifier.StateMachine for generating boilerplate
- Implement callback support in StateMachine GenServer:
  * State transition callbacks (enter, exit, transition)
  * Action callbacks (send, assign, log)
  * Lifecycle callbacks (init, snapshot)
- Add comprehensive test suite for macro system
- Support named GenServers and snapshot intervals
- All tests passing with 91.2% coverage

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
johnnyt and others added 17 commits September 4, 2025 05:49
This commit implements the foundational examples infrastructure for
demonstrating Statifier's GenServer-based workflow capabilities:

- **Purchase Order Approval Workflow**: Complete business process example
  - Multi-level approval routing based on amounts (≤$5K manager, >$5K exec)
  - SCXML definition with conditional transitions and data model
  - GenServer implementation with business logic callbacks
  - State persistence, logging, and comprehensive error handling

- **Examples Infrastructure**: Extensible framework for future workflows
  - Mix project with proper dependency management and path references
  - CLI interface for running and listing examples
  - Structured testing with @describetag :example tags
  - Demo scripts with realistic business scenarios

- **Production Patterns**: Real-world workflow engine foundations
  - Debug logging enabled by default for state machine visibility
  - Comprehensive test coverage for all approval paths
  - Documentation with usage examples and API reference
  - Callback system for notifications and business logic integration

- SCXML workflow definitions in approval_workflow/scxml/
- StateMachine modules using Statifier.StateMachine macro
- Comprehensive tests covering happy path and rejection scenarios
- Mix aliases for `examples.run` and `examples.test` commands
- Ready for Phase 2 enhancements (persistence, complex workflows)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit resolves the start_link/1 default argument conflict and
test tag placement issues that were preventing examples from compiling:

## Fixed Issues

- **start_link conflict**: Removed custom start_link/1 with defaults that
  conflicted with macro-generated function. Now uses generated start_link
  from Statifier.StateMachine macro without override.

- **@describetag placement**: Fixed @describetag placement inside describe
  blocks. Added module-level @tag :example as requested.

- **Compilation success**: Examples now compile and run successfully
  - `mix compile` works without errors
  - `mix examples.run list` shows available examples
  - `mix examples.run approval_workflow` executes demo

## Current Status

✅ **Infrastructure**: Examples compile and CLI works
❌ **Event data**: SCXML assign actions not working properly
❌ **Tests**: 6/8 tests failing due to event data issues

## Next Steps

Phase 1 infrastructure is complete but event data assignment needs debugging.
The SCXML expressions `_event.data.po_id` → `po_id` are not working as expected.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Maps internal :warn log level to :warning for compatibility with
Elixir 1.15+ which deprecated :warn in favor of :warning.

The fix maintains backward compatibility by keeping :warn as the
internal API while properly mapping to :warning when calling
Elixir's Logger functions.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updates StateMachine to properly pass log_level and log_adapter options
through to the Interpreter during initialization. This allows examples
to enable trace logging for detailed debugging of state machine execution.

Changes:
- StateMachine now extracts and passes interpreter options (log_level, log_adapter)
- Demo script updated to use log_level: :trace for all scenarios
- Removed custom handle_init that was trying to configure logging incorrectly
- Updated documentation to list available logging options

Note: Trace logs are generated but mapped to :debug level in Elixir's Logger
since it doesn't have a native :trace level. Ensure Logger.configure(level: :debug)
to see trace output.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
The examples config was using compile_time_purge_matching to remove
all logs below :info level at compile time, preventing debug and trace
logs from ever being generated.

Removed the compile-time purging and set default level to :debug to
allow trace logs (which map to debug in Elixir's Logger) to be shown
when requested.

Now when running examples with log_level: :trace, you will see:
- Processing microstep (trace level)
- Transition evaluations (debug level)
- Action executions (debug level)
- Configuration changes (debug level)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Auto-formatted code using mix format and applied Credo linting
suggestions across the codebase. Changes include:

- Consistent indentation and spacing
- Removed trailing whitespace and added final newlines
- Fixed line length violations
- Improved code readability and consistency

This maintains code quality standards while preserving all
functionality from the trace logging and examples implementation.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Core implementation migration with full code quality compliance:

- Migrates PurchaseOrderMachine from examples_old to umbrella app structure
- Updates module namespaces from Examples.ApprovalWorkflow to ApprovalWorkflow
- Relocates SCXML file to priv/scxml/purchase_order.xml in app structure
- Adds comprehensive @SPEC type specifications for all functions
- Implements proper module aliasing to eliminate nested module warnings
- Fixes unused variable naming for consistency (credo compliance)
- Adds formatter configuration for umbrella project with Statifier integration
- Updates tests to verify basic workflow functionality

The core state machine is now fully functional in the new structure with all
credo quality checks passing. Ready for Phase 2 comprehensive testing migration.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@johnnyt johnnyt changed the title Adds GenServer Adds StateMachine abstraction with umbrella examples Sep 5, 2025
@johnnyt johnnyt changed the title Adds StateMachine abstraction with umbrella examples Adds StateMachine GenServer with umbrella examples Sep 5, 2025
@johnnyt johnnyt changed the title Adds StateMachine GenServer with umbrella examples Adds StateMachine GenServer and examples Sep 5, 2025
@johnnyt johnnyt merged commit a601642 into main Sep 5, 2025
12 checks passed
@johnnyt johnnyt deleted the genserver branch September 5, 2025 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants