/**
 * OKR Cascade Service
 *
 * Owns the decompose → propose → approve/reject workflow for the OKR cascade
 * (company → team → project). A team-leader/PM agent drafts child OKRs as a
 * PROPOSAL; the child Missions are persisted with
 * `approval.state = 'pending_approval'` and are NOT cascade-active until the
 * human owner approves. Rejection carries a required reason.
 *
 * This service is the SINGLE owner of `approval.state` transitions — the
 * `updateMission` PUT route blocks direct `approval` writes so that all
 * transitions flow through {@link OKRCascadeService.approveDecomposition} and
 * {@link OKRCascadeService.rejectDecomposition} (spec §3.2/§3.3).
 *
 * FLAG (spec §2.5): the approval *workflow* (this service + its routes) is a
 * plausible future move to `crewly-pro` as a gated governance feature. The
 * approval *types* live in `mission.types.ts` and stay there; only this
 * workflow layer would relocate. Do NOT split now.
 *
 * Persistence reuses the existing on-disk layout:
 *   - Missions: `.crewly/missions/{id}.json`
 *   - KRs:      `.crewly/missions/{id}/key-results/` (via {@link KRTrackingService})
 *
 * @module services/v3/okr-cascade.service
 */
import { type Mission, type MissionLevel } from '../../types/v2/mission.types.js';
import type { CreateKeyResultInput } from '../../types/v2/key-result.types.js';
/**
 * A single proposed child OKR within a decomposition: one objective plus its
 * Key Results. `projectId` is required only when the resulting child level is
 * `project`.
 */
export interface DecomposeOKRChild {
    /** Objective statement for the child OKR. */
    objective: string;
    /** Strategic approach the child will pursue. */
    currentStrategy: string;
    /** Free-text success criteria (in addition to structured KRs). */
    successCriteria: string[];
    /** Required when the child level resolves to `project`. */
    projectId?: string;
    /**
     * Key Results to create under the child mission. `missionId` is filled in by
     * the service once the child mission id is known, so callers omit it.
     */
    keyResults: Array<Omit<CreateKeyResultInput, 'missionId'>>;
}
/**
 * Input to {@link OKRCascadeService.proposeDecomposition}: the set of child
 * OKRs to draft one tier below the parent mission.
 */
export interface DecomposeOKRInput {
    /** One entry per proposed child mission. */
    children: DecomposeOKRChild[];
}
/** Result of a successful {@link OKRCascadeService.proposeDecomposition} call. */
export interface ProposeResult {
    /** The parent mission that was decomposed. */
    parentId: string;
    /** Cascade level of every created child (parent level + 1). */
    childLevel: MissionLevel;
    /** IDs of the created (pending-approval) child missions. */
    childMissionIds: string[];
}
/**
 * Singleton service implementing the OKR decomposition / approval workflow.
 */
export declare class OKRCascadeService {
    private static instance;
    private readonly logger;
    private constructor();
    /**
     * Get the singleton instance.
     *
     * @returns The shared {@link OKRCascadeService}
     */
    static getInstance(): OKRCascadeService;
    /**
     * Reset the singleton (for testing).
     */
    static resetInstance(): void;
    /**
     * Draft a child OKR decomposition for a parent mission as a PROPOSAL.
     *
     * The parent must exist and be cascade-active (approval absent or
     * `approval.state === 'approved'`). The child level is computed as exactly one
     * tier below the parent; decomposing a `project`-level parent is rejected
     * (there is no tier below project). Each child mission is created with
     * `approval.state = 'pending_approval'` and is NOT active until the owner
     * approves. Each child's Key Results are created via {@link KRTrackingService}
     * (no duplicate KR persistence here).
     *
     * The decomposition is "fail before writing": EVERY child is fully validated
     * (project-id presence + cascade-link adjacency/cycle) BEFORE any mission or
     * KR is persisted, so a later invalid child never leaves an earlier child
     * half-written to disk.
     *
     * @param parentId - ID of the parent mission to decompose
     * @param input - The proposed child OKRs (objectives + KRs)
     * @param proposedBy - Agent session that drafted the proposal
     * @returns The parent id, resolved child level, and created child IDs
     * @throws If the parent is missing, not approved, already at `project` level,
     *   the input has no children, or a child fails cascade-link validation
     *
     * @example
     * ```ts
     * const result = await OKRCascadeService.getInstance().proposeDecomposition(
     *   'co-1',
     *   { children: [{ objective: 'Ship v2', currentStrategy: '...', successCriteria: [], keyResults: [] }] },
     *   'team-leader-session',
     * );
     * ```
     */
    proposeDecomposition(parentId: string, input: DecomposeOKRInput, proposedBy: string): Promise<ProposeResult>;
    /**
     * Approve a pending decomposition proposal, making the child mission
     * cascade-active. Guarded by {@link isValidProposalTransition} so only a
     * `pending_approval` mission may transition to `approved`.
     *
     * @param missionId - ID of the proposed (pending_approval) mission
     * @param decidedBy - Human owner who approved (e.g. "steve")
     * @returns The updated mission
     * @throws If the mission is missing, has no approval state, or the
     *   `pending_approval → approved` transition is illegal
     */
    approveDecomposition(missionId: string, decidedBy: string): Promise<Mission>;
    /**
     * Reject a pending decomposition proposal with a required reason. The
     * rejected mission is excluded from roll-up and autonomous execution.
     *
     * @param missionId - ID of the proposed (pending_approval) mission
     * @param decidedBy - Human owner who rejected (e.g. "steve")
     * @param reason - Non-empty explanation surfaced back to the proposing agent
     * @returns The updated mission
     * @throws If the reason is empty, the mission is missing, has no approval
     *   state, or the `pending_approval → rejected` transition is illegal
     */
    rejectDecomposition(missionId: string, decidedBy: string, reason: string): Promise<Mission>;
    /**
     * List missions awaiting an owner decision (`approval.state ===
     * 'pending_approval'`). Optionally scope to the direct children of one parent.
     *
     * @param parentId - When provided, only pending children of this parent
     * @returns Pending-approval missions
     */
    listPendingApprovals(parentId?: string): Promise<Mission[]>;
    /**
     * Whether a mission counts as cascade-active: approval absent (legacy) or
     * explicitly approved.
     *
     * @param mission - Mission to test
     * @returns `true` if the mission participates in the cascade
     */
    private isCascadeActive;
    /**
     * Resolve a mission's effective level through the SINGLE canonical resolver
     * shared with the routes' read-migration ({@link resolveMissionLevel}), which
     * prefers an explicit `level` and otherwise falls back to `deriveLevel` over
     * the parent chain. A parentless legacy mission therefore resolves to
     * `company` consistently across every read path.
     *
     * @param mission - Mission whose level to resolve
     * @param byId - All missions indexed by ID for the parent-chain walk
     * @returns The mission's resolved level
     */
    private resolveLevel;
    /**
     * Compute the cascade level exactly one tier below the given level.
     *
     * @param level - Parent level
     * @returns The child level, or `null` if `level` is already the bottom tier
     */
    private nextLevel;
    /** Absolute path to the missions directory under the current cwd. */
    private getMissionsDir;
    /** Absolute path to a single mission's JSON file. */
    private getMissionPath;
    /**
     * Validate + normalize a parsed mission document read from disk.
     *
     * - Returns `null` for anything that is not structurally a {@link Mission}
     *   (corrupt / hand-edited / wrong shape), so callers never trust junk.
     * - When `approval` is present but `approval.state` is NOT a recognized
     *   {@link isValidProposalState}, the state is normalized to
     *   {@link CORRUPT_APPROVAL_FALLBACK} (`rejected`). This deliberately treats a
     *   corrupt governance state as INACTIVE — neither cascade-active nor a
     *   recognized pending state — rather than silently trusting an unknown
     *   string (which would otherwise be neither active nor pending and could
     *   crash transition guards).
     *
     * @param value - Raw JSON-parsed value
     * @returns A validated, normalized Mission, or `null` if not a valid Mission
     */
    private sanitizeMission;
    /**
     * Load a single mission from disk, validated + normalized via
     * {@link sanitizeMission}.
     *
     * @param missionId - Mission ID
     * @returns The mission, or `null` if missing/unreadable/not a valid Mission
     */
    private loadMission;
    /**
     * Load all missions from disk, skipping unreadable AND structurally-invalid
     * files (each validated + normalized via {@link sanitizeMission}).
     *
     * @returns Array of valid missions
     */
    private loadAllMissions;
    /**
     * Persist a mission to disk (creating the missions directory if needed).
     *
     * @param mission - Mission to write
     */
    private persistMission;
}
//# sourceMappingURL=okr-cascade.service.d.ts.map