export type GoalPhase = "idle" | "planning" | "executing" | "verifying"; export type GoalStatus = | "active" | "user_paused" | "back_off_paused" | "no_progress_paused" | "infra_paused" | "blocked" | "budget_limited" | "complete"; export type GoalEvent = | "goal_created" | "planning_started" | "planning_completed" | "planning_failed" | "worker_started" | "goal_paused" | "goal_resumed" | "goal_completed" | "goal_cleared" | "budget_exceeded" | "verify_started" | "verify_achieved" | "verify_not_achieved" | "stall_paused" | "strategist_fired" | "progress" | "unknown"; export interface GoalHistoryEntry { timestamp: string; event: GoalEvent; detail?: string; round?: number; unmet?: string[]; } /** Durable, repository-local owner of a goal state. */ export interface GoalOwner { /** Pi session identity from ExtensionContext.sessionManager.getSessionId(). */ sessionId: string; /** Monotonic fencing token; increments on explicit takeover. */ generation: number; /** Diagnostic owner-activity lease; expiry never transfers ownership implicitly. */ leaseExpiresAt: string; } /** Stable portion of GoalOwner used to fence a persisted write. */ export interface GoalOwnerToken { sessionId: string; generation: number; } export interface SubgoalNode { id: string; title: string; status: "pending" | "active" | "done" | "blocked"; criteria: string[]; } export interface GoalOrchestration { goalId: string; objective: string; status: GoalStatus; phase: GoalPhase; createdAt: string; elapsedMs: number; history: GoalHistoryEntry[]; planPath: string; planBaselinePath: string; strategyPath?: string; verifierId: string; verifyAttempts: number; verifyMax: number; skepticN: number; lastGaps: string[]; lastGapFingerprint: string | null; stallCount: number; consecutiveNotAchieved: number; strategistEvery: number; tokenBudget?: number; tokenBaseline?: number; subgoals: SubgoalNode[]; pauseMessage?: string; lastStrategyRecommendation?: string; /** Consecutive blocked attempts; 3 → status blocked. */ blockedAttempts?: number; stallThreshold?: number; /** Planner subagent id while phase is planning (optional; for statusline). */ plannerAgentId?: string; /** Missing only on legacy state; it must be explicitly taken over before activation. */ owner?: GoalOwner; } export interface GoalConfig { enabled: boolean; /** Default 3, clamp 1–5. */ skepticN: number; /** Default 10. */ verifyMax: number; /** Default 2. */ stallThreshold: number; /** Default max(1, verifyMax/2). */ strategistEvery: number; plannerRequired: boolean; preverify: boolean; receipts: boolean; /** Per-skeptic / panel wait default 600s. */ subagentsTimeoutMs: number; /** Planner wait default 30m (separate from panel — B029). */ plannerTimeoutMs: number; } export const GOAL_STATUSES: readonly GoalStatus[] = [ "active", "user_paused", "back_off_paused", "no_progress_paused", "infra_paused", "blocked", "budget_limited", "complete", ] as const; export const GOAL_EVENTS: readonly GoalEvent[] = [ "goal_created", "planning_started", "planning_completed", "planning_failed", "worker_started", "goal_paused", "goal_resumed", "goal_completed", "goal_cleared", "budget_exceeded", "verify_started", "verify_achieved", "verify_not_achieved", "stall_paused", "strategist_fired", "progress", "unknown", ] as const;