Observable Workflow Runtime
ObservableWorkflow is the common read-only telemetry boundary. AutomationLoop and TypesafeCarouselStateMachine publish immutable WorkflowSnapshot values through WorkflowRegistry while active. Terminal Carousel and failed/cancelled loop telemetry remain registered until explicit reset() or stop() cleanup, so the final CI screenshot can retain the terminal decision. History is bounded to 64 decisions per workflow.
Typed Carousel
Carousel handlers map exhaustively from an enum and execute at most once per supplied game-tick number. A duplicate-tick pulse returns a duplicate_tick stay result without executing a handler or appending history. A handler returns stay, transitionTo, complete, or fail. Every result requires a stable reason code and may include display text. The builder rejects blank IDs, duplicate definitions, a missing initial state, and incomplete enum coverage.
TypesafeCarouselStateMachine<State> workflow =
TypesafeCarouselStateMachine.builder(State.class, "woodcutting.main")
.owner(this)
.initial(State.IDLE)
.on(State.IDLE, ctx -> CarouselResult.transitionTo(
State.WALK, "inventory_ready", "Walking to trees"))
.on(State.WALK, ctx -> atTrees()
? CarouselResult.transitionTo(State.CHOP, "arrived", "At trees")
: CarouselResult.stay("walking", "Waiting for arrival"))
.on(State.CHOP, ctx -> CarouselResult.complete("logs_cut", "Done"))
.build();
TypesafeCarouselStateMachine is the repository’s sole state-machine framework; new and existing workflows use its enum-exhaustive Carousel model.
Supervision and breaks
WorkflowSupervisor evaluates ordered cooperative guards between pulses. A guard returns RUN, SUSPEND, INTERRUPT, or CANCEL. Work resumes by executing the current handler again, so live preconditions re-evaluate. Closures never suspend mid-action. AutomationLoop retains its existing Break Handler gate and accepts an additional supervisor through its config.
Agent and CI telemetry
Authenticated GET /api/v1/workflow/status and the direct MCP tool n3_get_workflow_status return registered workflow snapshots, including retained terminal telemetry. TestRunnerPlugin writes schema-version 2 results and associates the registered snapshots with each captured screenshot in workflowTimeline. Existing result fields remain intact.
Input and configuration boundaries
Recorder-buffer backfill is not an action-dispatch mechanism and we have not added it. Synthetic AWT/native-click behavior remains opt-in and fails closed in UI suppression mode. Any future recorder experiment must be default-off, owned by Packet Utils, backed by revision-matched injected-client evidence, and live validated.
ConfigManager remains the runtime configuration authority. Headless agents should use the authenticated, scoped Agent Server plugin configuration methods; credential material stays in encrypted n3 Profiles or the memory-only login service. We intentionally do not introduce a second file-backed runtime configuration authority.
Live client verification: pending