/**
 * RequestCascadeSubscriber — keeps Request.status in sync with the
 * aggregate state of its child WorkItems by reacting to live task
 * lifecycle events on the central EventBus.
 *
 * **Why this exists.** 2026-05-09 dogfood: `cascadeRequestStatus` lives
 * inside V3DataService, but the only callers are V3DataService's
 * onTaskCompleted/onTaskFailed/onTaskBlocked handlers — and those
 * handlers are wired to the **retired** `v3:task_*` events that nothing
 * emits anymore (`mission-executor.service.ts:152` v1-cleanup comment).
 * So the cascade hadn't fired for any task event in months.
 *
 * Symptom: a Slack-originated Request whose 4 child WIs all landed in
 * `cancelled` stayed in `ready` for hours, generating misleading
 * "0/4, 进行中 0..." heartbeats every sweep.
 *
 * **What this subscribes to.** Every live task lifecycle event that the
 * central EventBus publishes:
 *   - `task:done_by_worker`   — child finished, awaiting verification
 *   - `task:verified`         — verifier accepted
 *   - `task:rejected`         — verifier sent back for retry
 *   - `task:cancelled`        — child cancelled (added in this PR)
 *   - `task:failed`           — child failed terminally
 *   - `task:blocked`          — child wedged
 *
 * Each handler resolves `requestId` from the event payload (or by
 * looking up the WI if the event didn't carry it) and calls
 * {@link cascadeRequestStatus}, which re-reads pool state and patches
 * the parent Request to the right status.
 *
 * **What this is NOT.** This is not a notification service —
 * `RequestStatusUpdateSubscriber` handles user-facing Slack updates.
 * They share the event stream but have separate concerns. (The
 * heartbeat-driven closer in `RequestStatusUpdateSubscriber` remains
 * as a 30-min safety net for any cancellation that bypasses the
 * publish path — e.g. direct storage mutation by an ops script.)
 *
 * @module services/v3/request-cascade.subscriber
 */
import { type ComponentLogger } from '../core/logger.service.js';
import type { EventBusService } from '../event-bus/event-bus.service.js';
import type { WorkItem } from '../../types/v2/work-item.types.js';
import { type CascadeRequestService, type CascadeTaskPool, type CascadeNotifier } from './cascade-request-status.js';
/**
 * Minimal pool surface — needs both `findWorkItem` (resolve missing
 * requestId from event payload) and `getAllItems` (the cascade itself
 * re-reads pool state).
 */
export interface CascadeSubscriberTaskPool extends CascadeTaskPool {
    findWorkItem(id: string): Promise<WorkItem | undefined | null>;
}
export interface RequestCascadeSubscriberDependencies {
    eventBus: EventBusService;
    requestService: CascadeRequestService;
    taskPool: CascadeSubscriberTaskPool;
    /** Optional notifier — production wiring passes the same EventBus so
     * `v3:request_updated` reaches existing UI subscribers. */
    notifier?: CascadeNotifier;
    logger?: ComponentLogger;
}
export declare class RequestCascadeSubscriber {
    private readonly eventBus;
    private readonly requestService;
    private readonly taskPool;
    private readonly notifier?;
    private readonly logger;
    private unsubscribers;
    private started;
    /** In-flight async dispatch promises — exposed via `flushPending` for tests. */
    private readonly pendingDispatches;
    constructor(deps: RequestCascadeSubscriberDependencies);
    /**
     * Subscribe to bus events. Idempotent.
     */
    start(): void;
    /**
     * Detach subscriptions. Safe to call repeatedly.
     */
    stop(): void;
    /**
     * Test affordance — wait for any in-flight dispatch promises to settle.
     */
    flushPending(): Promise<void>;
    private safeDispatch;
    private handleTaskEvent;
}
//# sourceMappingURL=request-cascade.subscriber.d.ts.map