import { SmrtObjectOptions } from '@happyvertical/smrt-core'; import { SupportCase } from '../models/support-case.js'; import { SupportAvailabilityCollection, SupportQualificationCollection, SupportSpecialistCollection } from '../models/support-specialist.js'; import { SupportPrincipal } from '../permissions.js'; import { SupportActorKind } from '../types.js'; import { SupportCaseService } from './support-case-service.js'; /** * Named scoring weights, so the ranking is auditable against the code. * Factors carry the raw signals; the score composes them with these weights. */ export declare const ROUTING_WEIGHTS: { /** Case/plan preferred specialist (FR-30) — considered first. */ readonly PREFERRED_SPECIALIST: 100; /** Effective `expert` Project Support Qualification. */ readonly QUALIFICATION_EXPERT: 30; /** Effective `qualified` Project Support Qualification. */ readonly QUALIFICATION_QUALIFIED: 20; /** Effective `trainee` Project Support Qualification. */ readonly QUALIFICATION_TRAINEE: 5; /** An active on-call span at the routing instant. */ readonly ON_CALL: 25; /** A weekly availability window covering the routing instant. */ readonly WEEKLY_AVAILABLE: 15; /** Maximum workload-headroom bonus (scaled by free capacity). */ readonly WORKLOAD_HEADROOM_MAX: 10; /** Case language ∈ specialist languages. */ readonly LANGUAGE_MATCH: 10; }; /** One specialist's routing evaluation for a case. */ export interface RankedSpecialist { specialistId: string; displayName: string; score: number; /** Whether every hard eligibility filter passed. */ eligible: boolean; /** The raw signals behind the score/eligibility (rationale display). */ factors: Record; } /** Result of an {@link SupportRoutingService.autoAssign} attempt. */ export interface AutoAssignResult { assigned: boolean; specialistId?: string; ranking: RankedSpecialist[]; } /** Thrown when a manual reassignment is refused (permission or tenant). */ export declare class ReassignDeniedError extends Error { constructor(message: string); } /** Options for {@link SupportRoutingService.create}. */ export interface SupportRoutingServiceOptions extends SmrtObjectOptions { /** Share an existing case service (and its collections) with the router. */ caseService?: SupportCaseService; } /** * The routing engine. Construct with {@link SupportRoutingService.create}. */ export declare class SupportRoutingService { readonly caseService: SupportCaseService; readonly specialists: SupportSpecialistCollection; readonly qualifications: SupportQualificationCollection; readonly availabilities: SupportAvailabilityCollection; protected constructor(collections: { caseService: SupportCaseService; specialists: SupportSpecialistCollection; qualifications: SupportQualificationCollection; availabilities: SupportAvailabilityCollection; }); static create(options: SupportRoutingServiceOptions): Promise; private resolveCase; /** * Rank every Support Specialist for a case at an instant. * * Hard eligibility filters — each recorded as a factor: * - `status` must be `active`; * - when the case carries a `projectId`, an *effective* Project Support * Qualification for that project (`projectQualification` is the level, * or `'expired'`/`'none'` on failure); * - open assigned cases below `maxConcurrentCases` (`openCases`, * `workloadExceeded`); * - available at `at`: a weekly window in the specialist's own timezone or * an active on-call span, and not inside a time-off span * (`weeklyAvailable`, `onCall`, `timeOff`). * * Ineligible specialists are returned too (`eligible: false`) so the UI * can show the failing factor. Sorted by score descending, then display * name, then id. */ rankSpecialists(caseRef: SupportCase | string, opts?: { at?: Date; exclude?: string[]; }): Promise; private evaluateSpecialist; /** * Assign the top eligible ranked specialist, recording the rationale * (winning factors plus the compact top of the ranking) on the assignment * event. When no one is eligible, records an unrouted `note` event with * the full ranking and returns `assigned: false`. */ autoAssign(caseRef: SupportCase | string, opts?: { at?: Date; exclude?: string[]; actorKind?: SupportActorKind; }): Promise; /** * Manual reassignment override (FR-30). Requires the * `support.reassign-case` permission split on the acting principal and * refuses cross-tenant acts; the assignment event carries * `{ manual: true, note }` as its rationale. */ reassign(caseRef: SupportCase | string, input: { specialistId: string; principal: SupportPrincipal; note?: string; }): Promise; } export default SupportRoutingService; //# sourceMappingURL=support-routing-service.d.ts.map