/**
 * Task Pool Service — Unified task entry and queue management
 *
 * The Task Pool holds execution-ready WorkItems. Agents claim items
 * from the pool, and the Reconciler returns unclaimed or failed items.
 *
 * CEO Decision: Pool only holds execution-ready WorkItems, not all ProjectTasks.
 *
 * @module services/task-pool/task-pool.service
 */
import { PoolStorage } from './pool-storage.js';
import { ClaimService, type HeartbeatResult, type ExtendLeaseResult, type ExpiredClaimsSummary } from './claim.service.js';
import type { WorkItem, WorkItemStatus, WorkItemType, WorkItemOwner } from '../../types/v2/work-item.types.js';
import { type TaskClaim } from '../../types/v2/claim.types.js';
import type { EventBusService } from '../event-bus/event-bus.service.js';
/**
 * Narrow Request-link contract consumed by {@link TaskPoolService.addToPool}.
 *
 * Defined as a duck-typed interface (rather than importing the full
 * `RequestService` class) so tests can supply fakes without depending on
 * the RequestService transitive imports, and to keep the dependency
 * direction one-way: TaskPool → Request, never the reverse.
 *
 * P1 Bug B (Pool umbrella WI 72ca743a-3a66-4d0e-a6cf-1a861f849dbd):
 * the production `linkWorkItem` is idempotent — it short-circuits when
 * `workItemId` is already in `request.workItemIds[]` — so the
 * intrinsic-link path here is safe to coexist with downstream
 * subscriber-driven linking (request-sla.subscriber, V3DataService).
 */
export interface IRequestWorkItemLinker {
    /**
     * Idempotently link a WorkItem id to a Request's workItemIds[].
     *
     * @param requestId - The parent Request id (already on the WI).
     * @param workItemId - The WorkItem id to link.
     * @returns The updated Request, or null if the Request was not found.
     *   `addToPool` ignores the return value — link failure is best-effort.
     */
    linkWorkItem(requestId: string, workItemId: string): Promise<unknown>;
}
/** Result of {@link TaskPoolService.removeFromPool}. */
export interface RemoveFromPoolResult {
    /** `true` when the WorkItem existed and was removed. */
    removed: boolean;
    /** The deleted WorkItem (only when removed === true). */
    workItem?: WorkItem;
    /** `true` when an active claim was found at delete time. */
    hadActiveClaim?: boolean;
    /** Cause when removed === false. */
    reason?: 'not_found';
}
/**
 * Structured error thrown by {@link TaskPoolService.removeFromPool}
 * when an active claim exists and `force: true` was not passed.
 */
export declare class WorkItemClaimedError extends Error {
    readonly workItemId: string;
    readonly claimId: string;
    readonly claimedBy: string;
    constructor(args: {
        workItemId: string;
        claimId: string;
        claimedBy: string;
    });
}
/**
 * Filters for claiming work items from the pool.
 */
export interface PoolFilters {
    /** Only match items of these types */
    types?: WorkItemType[];
    /** Only match items with this owner role */
    owner?: WorkItemOwner;
    /** Only match items targeting a specific agent/team */
    target?: string;
    /** Only match items belonging to this mission */
    missionId?: string;
}
/**
 * Statistics snapshot of the pool's current state.
 */
export interface PoolSnapshot {
    /** Total items in the pool (all statuses) */
    total: number;
    /** Items available for claiming (queued, no active claim) */
    available: number;
    /** Items currently claimed by an agent */
    claimed: number;
    /** Average wait time in ms for items that have been claimed */
    avgWaitTimeMs: number;
    /** Breakdown by WorkItem type */
    byType: Record<string, number>;
    /** Breakdown by status */
    byStatus: Record<string, number>;
    /** ISO8601 timestamp of this snapshot */
    timestamp: string;
}
/**
 * Result returned when claiming a work item.
 *
 * `alreadyHeld` (Steve 2026-05-15, issue #513): true when the caller
 * already had an active claim — we return that claim + its WorkItem
 * instead of returning null. Callers (skill scripts, controller) can
 * distinguish "fresh claim" from "you already own this" and route
 * accordingly. Default `false` for new claims so existing callers
 * stay source-compat.
 */
export interface ClaimResult {
    /** The claimed work item */
    workItem: WorkItem;
    /** The claim object tracking the lease */
    claim: TaskClaim;
    /** Set when the caller already held an active claim before this call */
    alreadyHeld?: boolean;
}
/**
 * TaskPoolService manages the lifecycle of execution-ready WorkItems.
 *
 * Core operations:
 * - {@link addToPool} — enqueue an execution-ready WorkItem
 * - {@link claimFromPool} — agent claims the next available item
 * - {@link releaseBack} — release a claimed item back to the pool
 * - {@link getPoolStatus} — snapshot of pool statistics
 *
 * @example
 * ```typescript
 * const pool = TaskPoolService.getInstance();
 * pool.addToPool(workItem);
 * const result = pool.claimFromPool('agent-leo', { types: ['delegate'] });
 * if (result) {
 *   // agent works on result.workItem
 *   // when done:
 *   pool.completeItem(result.workItem.id);
 * }
 * ```
 */
export declare class TaskPoolService {
    private static instance;
    private readonly storage;
    private readonly claimService;
    private readonly logger;
    /**
     * Optional EventBus reference — wired via {@link setEventBusService} from
     * the boot path. When set, {@link addToPool} publishes a `workitem:queued`
     * event so subscribers (notably {@link RequestSlaSubscriber}) can react to
     * queue mutations. Optional because singleton callers (tests, CLI) bring
     * up the pool before the bus exists; missing bus is treated as a no-op
     * publish at warn level.
     */
    private eventBus;
    /**
     * Optional Request-linker reference — wired via {@link setRequestService}
     * from the boot path. When set, {@link addToPool} pushes the new WI's id
     * into the parent `Request.workItemIds[]` immediately after the storage
     * flush, independent of any downstream subscriber.
     *
     * P1 Bug B (Pool umbrella WI 72ca743a) intrinsic-link contract:
     *  - The pre-fix path relied on `workitem:queued` / `task:delegated`
     *    subscribers (request-sla.subscriber, V3DataService) to backfill
     *    `Request.workItemIds[]`. Manual / programmatic / cron callers that
     *    bypass the standard event chain left Requests with
     *    `workItemIds=[]` even though their WIs were in the pool.
     *  - The intrinsic path here is the source-of-truth link and runs on
     *    every `addToPool`. Subscriber-driven linking remains as
     *    belt-and-suspenders (idempotent — see request.service.ts:328
     *    short-circuit on duplicate id).
     *  - Optional because singleton callers (tests, CLI) bring up the pool
     *    before RequestService exists; missing linker is a no-op debug log.
     */
    private requestService;
    /**
     * Optional agent-liveness probe — wired via {@link setIsAgentActive} from
     * the boot path. When set, {@link claimFromPool} and {@link claimSpecificItem}
     * refuse to issue a claim if the requesting agent's PTY session is not alive.
     *
     * Why: the invariant is that a WI in `running` status is being executed by
     * a live agent. The orchestrator's `delegate-task` skill pre-claims a fresh
     * WI for its target before the target session is actually spawned (see
     * `config/skills/orchestrator/delegate-task/execute.sh` "self-heal fix #1"
     * 2026-04). That pushes the WI from `queued` to `running` while the target
     * is still inactive. 5 s later the reconciler's `detectStuckWorkItems`
     * rule sees `running` + dead agent and marks the WI `blocked` — and the
     * reconciler's `detectUnclaimedTasks` wake-rule only handles `queued`
     * items, so the agent never gets spawned and the WI is stuck forever.
     *
     * Rejecting the claim at the source keeps the WI in `queued`, letting the
     * wake-rule do its job (start the agent → agent auto-claims when it boots).
     * delegate-task's existing fallback path (line 277 of execute.sh — "if
     * claim fails (race, target locked, etc.) the work proceeds via the
     * async path") already handles a rejected pre-claim gracefully.
     *
     * Optional because singleton callers (tests, CLI) bring up the pool
     * before any agent-registration plumbing exists; missing probe = "trust
     * the caller" (current behavior preserved for those code paths).
     */
    private isAgentActive;
    /**
     * Serializes claim operations to prevent the race where two concurrent
     * claimFromPool / claimSpecificItem calls both select the same queued
     * WorkItem between their read and write phases. In-process only — does
     * not protect against cross-process races, but the backend runs as a
     * single process today.
     */
    private claimMutex;
    constructor(storage?: PoolStorage);
    /**
     * Wire the EventBus reference used by {@link addToPool} to publish
     * `workitem:queued` events (INBOUND-1.f1). Called from the backend boot
     * path after both services have been constructed. Idempotent and may be
     * called with `null` to disable publishing (testing).
     *
     * @param bus - The EventBus instance, or null to clear
     */
    setEventBusService(bus: EventBusService | null): void;
    /**
     * Wire the Request-linker reference used by {@link addToPool} to
     * intrinsically link the new WI into its parent `Request.workItemIds[]`
     * (P1 Bug B — Pool umbrella WI 72ca743a).
     *
     * Called from the backend boot path after both services exist.
     * Idempotent and may be called with `null` to disable intrinsic
     * linking (testing). Mirrors the {@link setEventBusService} setter
     * pattern so the dependency wiring stays uniform and grep-able.
     *
     * @param svc - The RequestService instance (or any object satisfying
     *   {@link IRequestWorkItemLinker}), or null to clear.
     */
    setRequestService(svc: IRequestWorkItemLinker | null): void;
    /**
     * Wire the agent-liveness probe used by {@link claimFromPool} and
     * {@link claimSpecificItem} to refuse claims for dead/missing target
     * sessions. Called from the backend boot path after the agent runtime
     * exists. Idempotent and may be called with `null` to disable the gate
     * (testing or single-process CLI).
     *
     * @param probe - Async function returning whether the named session is
     *   currently alive (PTY exists + child runtime running), or null to clear
     */
    setIsAgentActive(probe: ((agentId: string) => Promise<boolean>) | null): void;
    /**
     * Chains the given critical section after any in-flight claim operation.
     * Guarantees FIFO ordering even under concurrent invocation.
     */
    private withClaimLock;
    /**
     * Get singleton instance of TaskPoolService.
     *
     * @returns The singleton TaskPoolService
     */
    static getInstance(): TaskPoolService;
    /**
     * Reset singleton (for testing).
     */
    static resetInstance(): void;
    /**
     * Adds an execution-ready WorkItem to the pool.
     *
     * Accepted statuses:
     * - `queued`  — ready to run
     * - `blocked` — waiting on unresolved dependsOn; the resolver will promote
     *               it to `queued` when every upstream dep reaches terminal success.
     *
     * @param workItem - The work item to add
     * @throws Error if workItem is invalid or in an ineligible status
     */
    addToPool(workItem: WorkItem): Promise<void>;
    /**
     * P1 Bug B helper: intrinsically link a freshly-added WI into its
     * parent `Request.workItemIds[]`.
     *
     * Stays a separate method (vs inlining) so:
     *   1. The dependency on RequestService stays explicit and grep-able,
     *      mirroring {@link publishWorkItemQueued}.
     *   2. Future enqueue paths (e.g. a batch addAll) can route through
     *      the same linker for consistent behaviour.
     *   3. Error handling stays in one place — a thrown linker must NOT
     *      back out the pool mutation (the storage write already committed).
     *
     * @param workItem - The WI just persisted into the pool.
     */
    private linkWorkItemToRequest;
    /**
     * INBOUND-1.f1 helper: publish a `workitem:queued` event with correlation
     * ids the SLA subscriber needs (`requestId`, `missionId`, plus the new
     * `workItemId`). Called by {@link addToPool} after the storage flush.
     *
     * Stays a separate method (vs inlining) so:
     *   1. The dependency on EventBus stays explicit and grep-able.
     *   2. A future caller adding an alternate enqueue path (e.g. a batch
     *      addAll) can route through the same publisher for consistent
     *      observability.
     *   3. Error handling stays in one place — a thrown publisher must NOT
     *      back out the pool mutation (the storage write already committed).
     */
    private publishWorkItemQueued;
    /**
     * F1-BRIDGE-1 helper: publish `task:done_by_worker` after a successful
     * `submitForVerification` transition. The {@link EventToWorkItemBridge}
     * subscribes to this event and creates a verification WorkItem for the
     * resolved team-lead session.
     *
     * Stays a separate method (mirrors {@link publishWorkItemQueued}) so:
     *   1. The dependency on EventBus stays explicit and grep-able — Arch's
     *      grep guard checks both the type declaration AND a publish call
     *      site for `task:done_by_worker`.
     *   2. Error handling is uniform with the other publishers — a thrown
     *      bus must NOT back out the verified state transition; the storage
     *      flush has already committed.
     *   3. A future caller adding an alternate verification-submission path
     *      (e.g. an admin endpoint or a CLI) routes through the same publisher.
     *
     * The deterministic event id (`task:done_by_worker:${workItemId}`) keys
     * dedup so a redelivered submitForVerification (theoretical) collapses
     * through the bus without firing the bridge handler twice.
     */
    private publishTaskDoneByWorker;
    /**
     * F1-BRIDGE-1 helper: publish `task:rejected` after a successful
     * `verifyItem` transition with verdict='rejected'. The
     * {@link EventToWorkItemBridge} subscribes and either creates a retry
     * WI (`retryCount < maxRetries`) or escalates to a TL review WI with
     * `reviewReason='max_retries_exceeded'` at the cap.
     *
     * Mirrors {@link publishTaskDoneByWorker} for symmetry. Only the
     * verdict='rejected' branch reaches this publisher — `verdict='verified'`
     * does NOT publish (terminal-success path goes through
     * {@link resolveBlockedDependents}, which is not a bridge trigger).
     */
    private publishTaskRejected;
    /**
     * Publish `task:cancelled` whenever a WorkItem transitions to the
     * cancelled status via {@link updateItemStatus} or {@link transitionStatus}.
     *
     * **Why this exists.** 2026-05-09 dogfood: 4 child WIs of a Slack-
     * originated Request all landed in `cancelled` (orc-not-in-health-map
     * loop, fixed in #531) but the Request stayed in `ready` for hours.
     * `cascadeRequestStatus` only fires from V3DataService's task
     * handlers, which are wired to the retired `v3:task_*` events
     * (`mission-executor.service.ts:152` v1-cleanup comment) — so out-of-
     * band cancellations never reached cascade. The heartbeat sweep
     * eventually caught it (#533), but with up-to-30-min latency that
     * showed up as a misleading "0/4 in every bucket" ping in the user's
     * Slack thread.
     *
     * Publishing `task:cancelled` lets `RequestCascadeSubscriber` close
     * the Request within seconds of the last child cancelling, instead
     * of waiting for the heartbeat catch.
     *
     * Mirrors {@link publishTaskDoneByWorker} / {@link publishTaskRejected}
     * so the EventBus surface stays uniform.
     *
     * @param workItem - The WI snapshot AFTER the cancelled transition committed
     * @param previousStatus - The status it transitioned from (for the event payload)
     */
    private publishTaskCancelled;
    /**
     * Claims the next available WorkItem from the pool for an agent.
     *
     * Selection strategy: FIFO among matching unclaimed 'queued' items.
     * If a target filter is provided, only items targeting that agent are considered.
     *
     * @param agentId - Agent session name claiming the item
     * @param filters - Optional filters to narrow which items to consider
     * @returns The claimed work item and claim object, or null if nothing available
     */
    claimFromPool(agentId: string, filters?: PoolFilters): Promise<ClaimResult | null>;
    /**
     * Claims a specific WorkItem by ID for an agent.
     * Used by AgentAutoClaimService for score-based selection where the caller
     * already identified the best item (not FIFO).
     *
     * @param agentId - Agent session name claiming the item
     * @param workItemId - The specific WorkItem to claim
     * @returns The claimed work item and claim, or null if unavailable
     */
    claimSpecificItem(agentId: string, workItemId: string): Promise<ClaimResult | null>;
    /**
     * Releases a claimed WorkItem back to the pool.
     *
     * The item's status reverts to 'queued' and the claim is marked 'released'.
     *
     * @param workItemId - ID of the work item to release
     * @param reason - Why the item is being released
     * @throws Error if work item not found or not currently claimed
     */
    releaseBack(workItemId: string, reason: string): Promise<void>;
    /**
     * Decide whether a WorkItem requires TL verification before reaching a
     * terminal-success status.
     *
     * Default policy (VERIF-1):
     *   - `delegate` items default to *requires verification* — a worker
     *     marking their own delegated work as "done" should produce
     *     `done_by_worker` and wake the TL for sign-off.
     *   - All other types (`cron_run`, `notify`, `reconcile`, `check`,
     *     `confirm`, `review`, ...) default to simple completion (`done`).
     *
     * The default is overridable via `wi.metadata.requiresVerification`:
     *   - `true`  — force verification path even for non-delegate types
     *   - `false` — skip verification even for delegate types (this is the
     *     F-H affordance REVIEW-1 needs: review WIs are themselves the
     *     verification step, so they must NOT loop back to TL self-verify)
     *
     * @param wi - The WorkItem under inspection
     * @returns true when the verification path should fire
     */
    private requiresVerification;
    /**
     * Internal: release the active claim on a WorkItem (if any). Shared by
     * `completeSimpleItem` and `submitForVerification` because both
     * represent the worker handing the item back to the system.
     *
     * @param workItemId - WorkItem whose claim should be released
     * @param endReason - Reason recorded on the claim (`completed` /
     *   `submitted_for_verification`) for auditability
     */
    private releaseClaim;
    /**
     * Worker reports a delegated WorkItem as done and submits it for TL
     * verification.
     *
     * Transitions `running → done_by_worker` via {@link transitionStatus},
     * which enforces the V3 actor-role gate (`'agent'` is allowed; any
     * other role throws). The active claim is released as
     * `submitted_for_verification` so the TL queue is the only thing
     * blocking forward progress.
     *
     * Used by the `completeItem` facade for `delegate`-type items and any
     * item whose `metadata.requiresVerification === true`.
     *
     * @param workItemId - WorkItem id
     * @param actorRole - Role of the caller (`'agent'` for normal worker
     *   submissions; passed through to `isTransitionPermitted`)
     * @param result - Optional result payload to attach to the WorkItem
     * @returns The updated WorkItem, or `null` if the WI was deleted
     *   between the find and the update (race window)
     * @throws When the WorkItem is missing, the transition is invalid, or
     *   the actor is not permitted to perform `running → done_by_worker`.
     */
    submitForVerification(workItemId: string, actorRole: WorkItemOwner, result?: Record<string, unknown>): Promise<WorkItem | null>;
    /**
     * Worker (or system) marks a non-delegated WorkItem as fully done.
     *
     * Transitions `running → done` via {@link transitionStatus}. Used by
     * the `completeItem` facade for `cron_run`, `notify`, `reconcile`,
     * `check`, `confirm`, `review` types — anything whose lifecycle does
     * NOT include a TL verification step.
     *
     * The Reconciler service is the only system-actor caller and uses
     * `actorRole='system'`, which bypasses the actor check while still
     * respecting the state-machine legality check.
     *
     * @param workItemId - WorkItem id
     * @param actorRole - Role of the caller (`'agent'`, `'system'`, etc.)
     * @param result - Optional result payload to attach
     * @returns The updated WorkItem, or `null` if the WI was deleted
     *   between the find and the update (race window)
     * @throws When the WorkItem is missing, the transition is invalid, or
     *   the actor is not permitted to perform `running → done`.
     */
    completeSimpleItem(workItemId: string, actorRole: WorkItemOwner, result?: Record<string, unknown>): Promise<WorkItem | null>;
    /**
     * TL records a verdict on a WorkItem in `done_by_worker` status.
     *
     * `verified` advances to terminal success and unblocks dependents;
     * `rejected` parks the item until the TL re-queues it (which TRANS-1
     * gates to TL/orchestrator/system actors). Worker-actor calls throw
     * automatically via {@link transitionStatus}'s permission gate — we
     * do NOT need to add an explicit role check here, the matrix in
     * `TRANSITION_PERMISSIONS` handles it.
     *
     * @param workItemId - WorkItem id (must currently be `done_by_worker`)
     * @param actorRole - Role of the caller (`'team_lead'` or `'orchestrator'`
     *   for verify/reject; worker calls throw)
     * @param verdict - `'verified'` or `'rejected'`
     * @param comment - Optional reviewer comment recorded in `wi.error`
     *   (the field is reused — the WorkItem schema does not yet have a
     *   dedicated `verifierComment` slot; keeping this on `error` lets
     *   downstream UIs render TL feedback alongside failure causes)
     * @returns The updated WorkItem, or `null` on race-window deletion
     * @throws When the WorkItem is missing, the verdict is invalid, the
     *   transition is illegal, or the actor is not permitted to verify.
     */
    verifyItem(workItemId: string, actorRole: WorkItemOwner, verdict: 'verified' | 'rejected', comment?: string): Promise<WorkItem | null>;
    /**
     * Legacy facade — picks the verification path for the caller.
     *
     * Existing call sites (REST controller, task-management controllers,
     * V3 data service) invoke `completeItem(id, result)` without an
     * explicit actor role. The facade reads the WorkItem, applies the
     * {@link requiresVerification} policy, and dispatches to either
     * {@link submitForVerification} (delegate items / explicit opt-in)
     * or {@link completeSimpleItem} (everything else).
     *
     * The legacy actor role for these implicit callers is `'agent'`.
     * Migrations to explicit-actor calls can land in follow-up tickets
     * without touching the five call sites in this PR.
     *
     * @param workItemId - WorkItem id
     * @param result - Optional result payload
     * @throws When the WorkItem is missing or the underlying transition
     *   is rejected (invalid state, forbidden actor).
     */
    completeItem(workItemId: string, result?: Record<string, unknown>): Promise<void>;
    /**
     * Scans blocked WorkItems that list `completedId` in their `dependsOn` and
     * promotes each to `queued` if every one of their deps has reached terminal
     * success (`done` or `verified`). Idempotent and safe to call on any terminal
     * success transition.
     *
     * Serialized via the claim mutex — a concurrent claimFromPool call must not
     * observe a half-promoted item.
     */
    resolveBlockedDependents(completedId: string): Promise<void>;
    /**
     * Marks a work item as failed.
     *
     * @param workItemId - ID of the work item
     * @param error - Error description
     * @throws Error if work item not found or not in 'running' status
     */
    failItem(workItemId: string, error: string): Promise<void>;
    /**
     * Cancel a WorkItem that is currently `queued` or `blocked` (i.e. has
     * NOT been claimed yet).
     *
     * Closes the 2026-05-25 #609 incident: a fallback delegate WI targeted
     * at `crewly-orc` got stuck `queued` and kept re-dispatching every
     * minute. The available APIs were either inappropriate (`fail` requires
     * `running`, `complete` requires `running`) or destructive (`DELETE
     * /api/task-pool/:id?force=1` is a hard delete with no audit trail).
     * This method provides the clean `queued → cancelled` transition with
     * a reason captured in `cancelReason` for the activity timeline.
     *
     * @param workItemId - Target WI id
     * @param reason     - Human-readable explanation; persisted on
     *                     `cancelReason` and surfaces in the UI badge.
     * @throws if the WI doesn't exist, has an active claim, or is in a
     *         non-cancellable terminal state.
     */
    cancelQueued(workItemId: string, reason: string): Promise<void>;
    /**
     * Requeue a failed WorkItem back to `queued` for another attempt.
     *
     * Path: `failed → queued` (legal in WORK_ITEM_TRANSITIONS but previously
     * unused — the system never auto-retried, every failure was terminal).
     * Increments `retryCount`, clears `startedAt`, preserves `target` so
     * the same agent gets a second shot, and records the previous error
     * on the WI's metadata for postmortem visibility.
     *
     * Caller must have ALREADY confirmed `retryCount < maxRetries` — this
     * method does NOT enforce the cap, on the assumption that the caller
     * (v3-data.onTaskFailed) handles the exhausted-retries branch with
     * escalation to ORC.
     *
     * @param workItemId - The failed WI to retry
     * @param reason     - Why the previous attempt failed (recorded on
     *   metadata.lastFailureReason; surfaces in the activity timeline)
     * @throws if the WI doesn't exist or isn't in `failed` status
     */
    requeueAfterFailure(workItemId: string, reason: string): Promise<void>;
    /**
     * Processes a heartbeat from an agent for their active claim.
     *
     * @param claimId - The claim ID
     * @param agentId - The agent sending the heartbeat
     * @returns HeartbeatResult
     */
    heartbeat(claimId: string, agentId: string): Promise<HeartbeatResult>;
    /**
     * Extends the lease on a claim.
     *
     * @param claimId - The claim ID
     * @param agentId - The agent requesting extension
     * @returns ExtendLeaseResult
     */
    extendLease(claimId: string, agentId: string): Promise<ExtendLeaseResult>;
    /**
     * Scans for expired claims (for Reconciler use).
     *
     * @param now - Current timestamp in ms
     * @returns Summary of expiring and grace-exceeded claims
     */
    scanExpiredClaims(now?: number): Promise<ExpiredClaimsSummary>;
    /**
     * Agents that look HUNG — they keep claiming work but never heartbeat, so
     * their claims are repeatedly grace-revoked. Powers the `/health`
     * orchestrator-liveness signal ("up but stalled") and hung-session recovery.
     *
     * @param threshold - Minimum consecutive grace-revokes to count as hung.
     * @returns Agent ids that currently look hung.
     */
    getHungAgents(threshold?: number): string[];
    /**
     * Clear an agent's hung state after a recovery (session restart), so the
     * restarted session is not immediately re-flagged before it can heartbeat.
     *
     * @param agentId - The agent/session id to clear.
     */
    clearHungState(agentId: string): void;
    /**
     * Revokes a claim and releases the work item back to the pool.
     * Used by the Reconciler when a claim's grace period is exceeded.
     *
     * @param claimId - The claim to revoke
     * @param reason - Reason for revocation
     */
    revokeAndRelease(claimId: string, reason: string): Promise<void>;
    /**
     * Exposes the underlying ClaimService for advanced operations.
     *
     * @returns The ClaimService instance
     */
    getClaimService(): ClaimService;
    /**
     * Returns a snapshot of pool statistics.
     *
     * @returns Pool statistics including counts and avg wait time
     */
    getPoolStatus(): Promise<PoolSnapshot>;
    /**
     * Returns all available (unclaimed, queued) work items.
     *
     * @param filters - Optional filters
     * @returns Array of available WorkItems
     */
    getAvailableItems(filters?: PoolFilters): Promise<WorkItem[]>;
    /**
     * Returns all work items in the pool (all statuses).
     *
     * @returns Array of all WorkItems
     */
    getAllItems(): Promise<WorkItem[]>;
    /**
     * Find a WorkItem by id without mutating it.
     *
     * Public read accessor used by callers that need to inspect a
     * specific item — for example REVIEW-1's reentrancy lock checks the
     * status of a Mission's `pendingReviewWorkItemId` to decide whether
     * to clear the lock. Returns `null` (not `undefined`) so callers can
     * use a uniform null-fallthrough idiom shared with
     * `getWorkItemSnapshot` and `transitionStatus`.
     *
     * @param workItemId - WorkItem id to look up
     * @returns The WorkItem, or `null` if no item has that id
     */
    findWorkItem(workItemId: string): Promise<WorkItem | null>;
    /**
     * Stores worker-supplied structured output on a WorkItem.
     *
     * Replaces the v1 `<taskId>.output.json` filesystem store with an
     * in-pool field (see {@link WorkItem.output}). Used by the worker
     * `complete-task` flow and read back by the TL `verify-output` skill.
     *
     * @param workItemId - WorkItem id to attach output to
     * @param output - Arbitrary task-specific output object
     * @returns The updated WorkItem, or null if not found
     */
    setOutput(workItemId: string, output: Record<string, unknown>): Promise<WorkItem | null>;
    /**
     * Reassigns a WorkItem to a different target agent.
     *
     * Replaces the v1 `/task-management/handoff` filesystem reassign with a
     * direct `target` field update on the WorkItem.
     *
     * Allowed transitions:
     *   - `target` must be a non-empty string
     *   - WI must not be in a terminal state (done/cancelled/failed-final)
     *
     * @param workItemId - WorkItem to reassign
     * @param newTarget  - Session name of the new target agent
     * @param fromAgent  - Session name of the agent handing off (for audit)
     * @param reason     - Human-readable reason recorded as a working-note
     * @returns The updated WorkItem, or null if not found
     */
    handoff(workItemId: string, newTarget: string, fromAgent: string, reason: string): Promise<WorkItem | null>;
    /**
     * Appends a working-state note to a WorkItem's metadata.notes array.
     *
     * Replaces v1 `/task-management/sync` and `/task-management/save-working-notes`,
     * both of which appended progress notes to the `.md` task body. With v1
     * retired, notes live on the WorkItem itself under `metadata.notes[]`.
     *
     * @param workItemId - WorkItem id
     * @param author - Session name of note author
     * @param note - Note content (free-form)
     * @returns The updated WorkItem, or null if not found
     */
    appendNote(workItemId: string, author: string, note: string): Promise<WorkItem | null>;
    /**
     * Removes a WorkItem from the pool entirely.
     * Used for purging old completed/cancelled items.
     *
     * @param workItemId - ID of the item to remove
     */
    removeItem(workItemId: string): Promise<void>;
    /**
     * Public delete API used by the bulk-cleanup script and the new
     * `DELETE /api/task-pool/:id` HTTP endpoint (P1 umbrella WI 1ffffb84
     * component a, Steve directive 2026-05-06: just-DELETE-not-backfill).
     *
     * Three guarantees over {@link removeItem}:
     *   1. Idempotent — `not_found` is a no-op return, not a throw.
     *   2. Claim-safety — refuses claimed delete unless `opts.force`.
     *   3. Audit log — single info-level log per removal.
     *
     * Force path also revokes the orphaned claim (status='revoked',
     * endedAt, endReason).
     */
    removeFromPool(workItemId: string, opts?: {
        force?: boolean;
    }): Promise<RemoveFromPoolResult>;
    /**
     * Forces an immediate flush of pool data to disk.
     * Called during graceful shutdown to prevent data loss.
     */
    flush(): Promise<void>;
    /**
     * Returns all active/expiring claims.
     * Used by the Reconciler to check lease health.
     *
     * @returns Array of active/expiring TaskClaims
     */
    getActiveClaims(): Promise<TaskClaim[]>;
    /**
     * Updates a work item's status directly.
     * Used by the Reconciler for corrections (e.g., stuck → blocked).
     *
     * Reconciler invocations pass through `actorRole='system'` (default) which
     * bypasses the per-role gate at {@link isTransitionPermitted} but still
     * enforces the state-machine via {@link isValidWorkItemTransition}. Other
     * callers MUST supply the actor's role so TRANS-1 V3 enforcement applies.
     *
     * @param workItemId - The work item ID
     * @param newStatus - The target status
     * @param actorRole - Role of the caller (defaults to `'system'` for Reconciler)
     * @throws Error if work item not found
     * @throws Error if transition is invalid (state machine — see WORK_ITEM_TRANSITIONS)
     * @throws Error if actor is not permitted (role check — see TRANSITION_PERMISSIONS)
     */
    updateItemStatus(workItemId: string, newStatus: WorkItemStatus, actorRole?: WorkItemOwner, 
    /**
     * Optional human-readable reason. Persisted on:
     *   - `WorkItem.cancelReason` when `newStatus === 'cancelled'`
     *   - `WorkItem.blockedReason` when `newStatus === 'blocked'` (Steve
     *     2026-05-15 dogfood — UI showed Blocked badge with no
     *     explanation)
     *   - Ignored for other status transitions.
     */
    reason?: string): Promise<void>;
    /**
     * Public guarded transition helper — TRANS-1's canonical entrypoint.
     *
     * Routes any externally-initiated WorkItem status change through the
     * combined state-machine + actor-role gates. Designed as the public API
     * VERIF-1 will call from `submitForVerification` / `verifyItem`, and as
     * the recommended path for any future caller that previously reached
     * for `storage.updateWorkItem` to flip status.
     *
     * Differences vs {@link updateItemStatus}:
     *   - Requires `actorRole` explicitly (no default) — forces the caller to
     *     decide the trust posture rather than silently inheriting `'system'`.
     *   - Accepts an optional `mutator` so callers can carry additional field
     *     updates (e.g. `result`, `error`, `completedAt`) atomically with the
     *     status flip — preventing races between status update and metadata
     *     attachment that direct `storage.updateWorkItem` callers risked.
     *
     * @param workItemId - The work item ID
     * @param newStatus - The target status
     * @param actorRole - Role of the caller (REQUIRED; pass `'system'` for trusted server-internal paths)
     * @param mutator - Optional additional WorkItem field updates applied atomically with the status change
     * @returns The updated WorkItem after the transition
     * @throws Error if work item not found
     * @throws Error if transition is invalid (state machine)
     * @throws Error if actor is not permitted (role check)
     *
     * @example
     * ```typescript
     * // VERIF-1 worker submitting for verification
     * await pool.transitionStatus(wiId, 'done_by_worker', 'agent', (wi) => {
     *   wi.result = output;
     * });
     *
     * // VERIF-1 TL verifying
     * await pool.transitionStatus(wiId, 'verified', 'team_lead');
     *
     * // VERIF-1 TL rejecting (allowed for TL only)
     * await pool.transitionStatus(wiId, 'rejected', 'team_lead', (wi) => {
     *   wi.error = 'Did not meet acceptance criteria';
     * });
     * ```
     */
    transitionStatus(workItemId: string, newStatus: WorkItemStatus, actorRole: WorkItemOwner, mutator?: (wi: WorkItem) => void, 
    /**
     * Optional human-readable reason. Routed by target status:
     *   - `cancelled` → persisted on `WorkItem.cancelReason`
     *   - `blocked`   → persisted on `WorkItem.blockedReason`
     *     (Steve 2026-05-15 dogfood)
     *   - other       → ignored
     * Applied BEFORE the caller's mutator runs so the mutator may
     * override if needed. Surfaces in the activity timeline so the
     * Blocked/Cancelled badges aren't opaque ("WorkItem was X.").
     * Parameter name retained as `cancelReason` for source compat;
     * effectively a generic transition reason.
     */
    cancelReason?: string): Promise<WorkItem | null>;
    /**
     * Update token usage and cost on a WorkItem.
     * Called after task completion when token data is available from TokenUsageService.
     *
     * @param workItemId - The work item ID
     * @param inputTokens - Number of input tokens consumed
     * @param outputTokens - Number of output tokens generated
     * @param cost - Total cost in USD
     * @returns True if the update was applied, false if WorkItem not found
     */
    updateTokenUsage(workItemId: string, inputTokens: number, outputTokens: number, cost: number): Promise<boolean>;
    /**
     * Marks a claim as 'expiring' (lease expired, within grace period).
     * Used by the Reconciler fast loop.
     *
     * @param claimId - The claim ID to mark
     */
    markClaimExpiring(claimId: string): Promise<void>;
    /**
     * Graceful shutdown — flush pending writes.
     */
    destroy(): Promise<void>;
    /**
     * Exposes underlying storage for advanced operations (e.g., Reconciler).
     *
     * @returns The PoolStorage instance
     */
    getStorage(): PoolStorage;
}
//# sourceMappingURL=task-pool.service.d.ts.map