Files
felixm 7d69a1f320 Generalize the focus controller into a harness hosting swappable modes
Loosen AntiDrift's session controller into Keel's general collect→brain→act
loop. A new internal/harness runs at most one mode.Mode at a time, fanning
async completions out to the web SSE and status-bar surfaces.

- internal/mode: the Mode contract (Kind/Command/View/Active) plus optional
  EvidenceConsumer and Expirer ports, and the surfacing Envelope.
- internal/mode/focus: the former session/domain/statemachine packages moved
  under the mode, now satisfying the harness contracts unchanged.
- internal/mode/offscreen: a one-shot away-from-desk mode built on the new
  ai.Proposer, which turns a life-domain brief into one off-screen action.
- cmd/keeld replaces cmd/antidriftd; daemon wires focus + offscreen factories
  with per-mode persistence under ~/.keel/modes/<kind>.
- Finish the rename: KEEL_* env refs in the README, /keeld build artifact
  ignored, stale antidriftd binary removed.

Include the design + implementation plan this refactor was built from under
docs/superpowers/{specs,plans}/2026-06-04-controller-refactor*.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 18:00:49 -04:00

116 lines
5.0 KiB
Go

// Package statemachine holds the pure runtime and commitment transition
// functions. No I/O, no shared state.
package statemachine
import (
"fmt"
"keel/internal/mode/focus/domain"
)
// RuntimeAction enumerates runtime transitions. Activate's policy acceptance
// and admin-override exit targets are flattened into distinct actions so the
// action type stays a simple value.
type RuntimeAction string
const (
EnterPlanning RuntimeAction = "enter_planning"
CancelOrTimeout RuntimeAction = "cancel_or_timeout"
ActivateAccepted RuntimeAction = "activate_accepted"
ActivateRejected RuntimeAction = "activate_rejected"
StartTransition RuntimeAction = "start_transition"
CompleteForReview RuntimeAction = "complete_for_review"
SevereViolation RuntimeAction = "severe_violation"
ReturnToActive RuntimeAction = "return_to_active"
SwitchTask RuntimeAction = "switch_task"
EndTransitionForReview RuntimeAction = "end_transition_for_review"
ContinuePlanning RuntimeAction = "continue_planning"
EndWorkPeriod RuntimeAction = "end_work_period"
EnterAdminOverride RuntimeAction = "enter_admin_override"
ExitAdminOverrideToLocked RuntimeAction = "exit_admin_override_to_locked"
ExitAdminOverrideToPlanning RuntimeAction = "exit_admin_override_to_planning"
)
type CommitmentAction string
const (
CommitmentActivate CommitmentAction = "activate"
PauseForTransition CommitmentAction = "pause_for_transition"
ReturnFromPause CommitmentAction = "return_from_pause"
Complete CommitmentAction = "complete"
Abandon CommitmentAction = "abandon"
Violate CommitmentAction = "violate"
RecoverExplicitly CommitmentAction = "recover_explicitly"
)
// IllegalTransitionError reports a rejected transition.
type IllegalTransitionError struct {
From string
Action string
}
func (e IllegalTransitionError) Error() string {
return fmt.Sprintf("illegal transition from %s via %s", e.From, e.Action)
}
// PolicyRejectedError reports an activation attempted with an unaccepted policy.
type PolicyRejectedError struct{}
func (PolicyRejectedError) Error() string { return "policy was rejected" }
func TransitionRuntime(current domain.RuntimeState, action RuntimeAction) (domain.RuntimeState, error) {
type key struct {
s domain.RuntimeState
a RuntimeAction
}
table := map[key]domain.RuntimeState{
{domain.RuntimeLocked, EnterPlanning}: domain.RuntimePlanning,
{domain.RuntimePlanning, ActivateAccepted}: domain.RuntimeActive,
{domain.RuntimePlanning, CancelOrTimeout}: domain.RuntimeLocked,
{domain.RuntimeActive, StartTransition}: domain.RuntimeTransition,
{domain.RuntimeActive, CompleteForReview}: domain.RuntimeReview,
{domain.RuntimeActive, SevereViolation}: domain.RuntimeLocked,
{domain.RuntimeTransition, ReturnToActive}: domain.RuntimeActive,
{domain.RuntimeTransition, SwitchTask}: domain.RuntimePlanning,
{domain.RuntimeTransition, EndTransitionForReview}: domain.RuntimeReview,
{domain.RuntimeTransition, CancelOrTimeout}: domain.RuntimeLocked,
{domain.RuntimeReview, ContinuePlanning}: domain.RuntimePlanning,
{domain.RuntimeReview, EndWorkPeriod}: domain.RuntimeLocked,
{domain.RuntimeAdminOverride, ExitAdminOverrideToLocked}: domain.RuntimeLocked,
{domain.RuntimeAdminOverride, ExitAdminOverrideToPlanning}: domain.RuntimePlanning,
}
if action == ActivateRejected && current == domain.RuntimePlanning {
return current, PolicyRejectedError{}
}
if action == EnterAdminOverride {
return domain.RuntimeAdminOverride, nil
}
if next, ok := table[key{current, action}]; ok {
return next, nil
}
return current, IllegalTransitionError{From: string(current), Action: string(action)}
}
func TransitionCommitment(current domain.CommitmentState, action CommitmentAction) (domain.CommitmentState, error) {
type key struct {
s domain.CommitmentState
a CommitmentAction
}
table := map[key]domain.CommitmentState{
{domain.CommitmentDraft, CommitmentActivate}: domain.CommitmentActive,
{domain.CommitmentActive, PauseForTransition}: domain.CommitmentPaused,
{domain.CommitmentPaused, ReturnFromPause}: domain.CommitmentActive,
{domain.CommitmentActive, Complete}: domain.CommitmentCompleted,
{domain.CommitmentActive, Abandon}: domain.CommitmentAbandoned,
{domain.CommitmentActive, Violate}: domain.CommitmentViolated,
{domain.CommitmentPaused, Abandon}: domain.CommitmentAbandoned,
{domain.CommitmentViolated, RecoverExplicitly}: domain.CommitmentActive,
{domain.CommitmentViolated, Abandon}: domain.CommitmentAbandoned,
}
if next, ok := table[key{current, action}]; ok {
return next, nil
}
return current, IllegalTransitionError{From: string(current), Action: string(action)}
}