Issue #3608380: Finish the engine architecture: role contract interfaces, a TimeoutSweeper service, a stateless executor and unit coverage for the leaf services
The four finishing moves from the issue, one MR:
- Role interfaces on the contract, before 1.0 freezes it:
ProcessControlInterface(start, advance, signal, resume, cancel, spawn, variables, correlation lookup),IncidentActionsInterface(the five operator actions) andRecoveryInterface(the three sweeps plusarmJoinTimeouts()).WorkflowEngineInterfacenow extends all three and keeps its constants, so every existing type hint keeps working;Hook\WorkflowDeletiondemonstrates the narrowing by hintingProcessControlInterface. - TimeoutSweeper (
orchestra.timeout_sweeper): the 640-line cron sweep logic moved out of the Hook class, which is now a 37-line cron entry point. The sweeper depends on the collaborators it actually uses (executor, InstanceRecovery, DefinitionResolver, DeadlineCalculator, SubprocessCoordinator) instead of type-hinting the concreteWorkflowEnginefor its extra publics; the orchestra_ui "fire now" action now calls it directly. - Stateless executor: the inline-drain depth and per-request advance budget moved to a small
DrainStateholder, the one deliberately mutable object; every engine service is now immutable after construction. - Unit coverage for the pure leaves:
DurationTest(deadlines, absolute-date coercion with the relative-expression rejections, signed calendar offsets) andJoinOutcomeTest(the wait/fire factory contract the executor applies). The unit suite runs in 41 milliseconds, starting the shift of engine coverage down the pyramid.
No public signature changes anywhere. Verified locally: root kernel (183), unit plus all submodule kernel (333), all Functional in Docker (37), FunctionalJavascript (6), phpcs, cspell, phpstan parity.