Iterative cycles, thin vertical slices. Each cycle produces working, tested code.
See docs/plan/*.md for detailed design rationale.
See docs/tmp/implementation-sketches.md for rough code sketches.
The simplest system demonstrating core patterns working together.
- Single Ractor, global namespace
-
register(name, ractor)/lookup(name)/unregister(name) - Auto-unregister on Ractor death (via monitor)
- Thread-safe via message passing (no locks)
-
start_linkspawns Ractor with message loop - Call pattern (request + reply port)
- Cast pattern (fire-and-forget)
- Shutdown handling
- WorkerHandle for callers
- Static child specs
-
:one_for_onestrategy only - Restart bounding (max_restarts / within_seconds)
- Escalation on exceeded restarts (supervisor dies)
- Monitor all children
- Shutdown in reverse start order
- Registry: register, lookup, auto-cleanup, collision error (26 tests)
- Worker: call, cast, shutdown, crash notification (23 tests)
- Supervisor: start children, restart on death, escalation, shutdown (13 tests)
- Integration: Supervisor + Worker + Registry together
The "boring root" that enables "let it crash."
- Signal handling (TERM, INT → shutdown; PIPE ignored)
- Bootstrap phase (start kernel Ractors, then applications)
- Registry as kernel Ractor (death = halt)
- Steady-state loop (select on signals + monitors)
- Shutdown sequence (reverse order, timeouts)
- Check for shutdown between bootstrap phases
- Named bundle of child specs
- Dependency declaration (for ordering)
- Start = create supervisor with children
- Stop = shutdown supervisor
- Boot with no apps, verify running
- SIGTERM triggers graceful shutdown
- Kill kernel Ractor → system halts
- Application starts and is monitored
- Full stack integration test
Based on learnings from Cycles 1-2.
Candidates (prioritize based on what we learn):
-
:permanent/:transient/:temporaryrestart types - Application lifecycle hooks (prepare, running, stopping)
- Named worker registration (worker self-registers)
- DynamicSupervisor (runtime child creation)
- Better dead-Ractor identification (if race condition bites us)
- Health check endpoint
Umi::Proctor- external process wrapperUmi::MCPClient- MCP client on Proctor- Timer port pattern (in Proctor)
- Spikes validating all Ruby 4.0 primitives
The existing Proctor and MCP tests use a standalone script format with custom assertion helpers. Consider migrating to Minitest for consistency:
test/proctor_test.rb- standalone scripttest/proctor_api_test.rb- standalone scripttest/mcp_client_test.rb- standalone scripttest/mcp_chaos_test.rb- standalone script (chaos injection)test/proctor_stress_test.rb- standalone script (stress tests)
Benefits: unified test runner, consistent assertion API, better IDE integration. Risk: high - these tests are well-proven and modifications could introduce bugs.
- Force-kill mechanism - does Ruby 4.0 have
Ractor.kill? If not, what's the fallback? - Dead Ractor identification - is
find { !alive? }race acceptable or needs mitigation? - Registry shutdown protocol - stop accepting registrations? notify registered Ractors?
- Worker self-registration timing - before or after init completes?