@happyvertical/smrt-support 0.51.32 → 0.51.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/index.d.ts +17 -0
  2. package/dist/index.js +1 -1
  3. package/dist/manifest.json +1 -1
  4. package/dist/migrations/moneyMinorUnits.d.ts +30 -1
  5. package/dist/models/service-time-entry.d.ts +2 -1
  6. package/dist/models/support-ai-run.d.ts +11 -1
  7. package/dist/models/support-case-event.d.ts +11 -1
  8. package/dist/models/support-case.d.ts +13 -2
  9. package/dist/models/support-channel-binding.d.ts +11 -1
  10. package/dist/models/support-compensation-plan.d.ts +11 -0
  11. package/dist/models/support-interaction.d.ts +12 -1
  12. package/dist/models/support-plan.d.ts +19 -1
  13. package/dist/models/support-policy.d.ts +11 -0
  14. package/dist/models/support-service-target.d.ts +15 -1
  15. package/dist/models/support-settlement.d.ts +20 -1
  16. package/dist/models/support-specialist.d.ts +15 -1
  17. package/dist/models/support-work-link.d.ts +13 -1
  18. package/dist/permissions.d.ts +12 -1
  19. package/dist/services/coverage-calendar.d.ts +22 -1
  20. package/dist/services/human-handoff-service.d.ts +18 -3
  21. package/dist/services/project-assistance-adapter.d.ts +2 -2
  22. package/dist/services/service-target-engine.d.ts +33 -6
  23. package/dist/services/service-time-entry-service.d.ts +15 -3
  24. package/dist/services/support-ai-workflow.d.ts +22 -5
  25. package/dist/services/support-case-service.d.ts +15 -7
  26. package/dist/services/support-intake-service.d.ts +25 -4
  27. package/dist/services/support-plan-admin-service.d.ts +17 -4
  28. package/dist/services/support-routing-service.d.ts +19 -4
  29. package/dist/services/time-entry-approval-service.d.ts +33 -6
  30. package/dist/smrt-knowledge.json +4 -4
  31. package/package.json +11 -11
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-support",
5
- "packageVersion": "0.51.32",
5
+ "packageVersion": "0.51.35",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-support:ServiceTimeEntry": {
8
8
  "name": "servicetimeentry",
@@ -1,4 +1,33 @@
1
- import { DatabaseInterface, MinorUnitsPreflightResult, MinorUnitsRescaleResult, MoneyColumnTarget } from '@happyvertical/smrt-core/migrations';
1
+ /**
2
+ * Support money columns: floating-point major units → integer minor units.
3
+ *
4
+ * Ships as an explicit, opt-in migration rather than a schema-differ upgrade
5
+ * because REAL→INTEGER is not information-preserving: an automatic
6
+ * `ALTER … TYPE integer` would truncate `19.99` to `19`. The values have to be
7
+ * rescaled by the currency's minor-unit factor during the type change (#2401).
8
+ *
9
+ * ```ts
10
+ * console.log((await preflightSupportMoneyMinorUnits(db)).summary);
11
+ * await migrateSupportMoneyToMinorUnits(db);
12
+ * ```
13
+ *
14
+ * **Rate columns are deliberately absent.** `SupportPlan.overageHourlyRate`,
15
+ * `SupportPlan.onCallHourlyRate` and `SupportCompensationPlan.hourlyRate` stay
16
+ * DECIMAL — a rate is inherently fractional — but their *unit* changes from
17
+ * major units per hour to **minor units per hour**, so existing rows must be
18
+ * multiplied by the same scale. That is a value change with no type change, and
19
+ * the column list below cannot express it; rescale them in the same deploy
20
+ * step, e.g. `UPDATE support_plans SET overage_hourly_rate = overage_hourly_rate * 100`.
21
+ *
22
+ * Frozen `rateSnapshot` JSON on already-settled charges is history and is left
23
+ * alone: it records what the rate was when the charge was priced, and the
24
+ * amount beside it is rescaled by this migration.
25
+ *
26
+ * On SQLite the values are rescaled but the declared type cannot change in
27
+ * place; those columns come back in `declaredTypeChangePending` and need the
28
+ * table-rebuild path (#2370).
29
+ */
30
+ import { type DatabaseInterface, type MinorUnitsPreflightResult, type MinorUnitsRescaleResult, type MoneyColumnTarget } from '@happyvertical/smrt-core/migrations';
2
31
  /** Marker recorded in `_smrt_backfills` once the rescale has run. */
3
32
  export declare const SUPPORT_MONEY_MINOR_UNITS_BACKFILL = "@happyvertical/smrt-support:money-minor-units:v1";
4
33
  /** Every support money column that held major units before #2401. */
@@ -1,5 +1,6 @@
1
+ /** Compatibility mapping for issue #1955. */
1
2
  import { SmrtCollection } from '@happyvertical/smrt-core';
2
- import { ServiceParticipantKind, ServiceTimeEntrySource, ServiceTimeEntryStatus, ServiceTimeEntry as SharedServiceTimeEntry } from '@happyvertical/smrt-projects';
3
+ import { type ServiceParticipantKind, type ServiceTimeEntrySource, type ServiceTimeEntryStatus, ServiceTimeEntry as SharedServiceTimeEntry } from '@happyvertical/smrt-projects';
3
4
  /**
4
5
  * Source-compatible support subtype over the shared canonical table. The
5
6
  * fields are restated because package-isolated manifest scanning deliberately
@@ -1,5 +1,15 @@
1
+ /**
2
+ * SupportAiRun — the auditable record of one Automated Support Response phase
3
+ * (FR-28a): what the AI attempted (acknowledge / classify / answer /
4
+ * troubleshoot / resolve), with confidence, classification output, knowledge
5
+ * references, attempted tool calls, and outcome. This is the "prior automated
6
+ * work" a Human Handoff transfers losslessly (FR-28b).
7
+ *
8
+ * Append-only: generated surface is `list`/`get`; the workflow writes each
9
+ * run once and never rewrites history.
10
+ */
1
11
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { SupportAiRunOutcome, SupportAiRunPhase } from '../types.js';
12
+ import { type SupportAiRunOutcome, type SupportAiRunPhase } from '../types.js';
3
13
  export declare class SupportAiRun extends SmrtObject {
4
14
  tenantId: string | null;
5
15
  caseId: string;
@@ -1,5 +1,15 @@
1
+ /**
2
+ * SupportCaseEvent — append-only audit trail for a Support Case: creations,
3
+ * transitions, assignments, AI runs, handoffs, escalations, target state
4
+ * changes, work links, and reopens. Together with interactions this is the
5
+ * "complete Case context" a Human Handoff transfers (FR-28b) and the reopen
6
+ * history FR-29b preserves.
7
+ *
8
+ * Events are immutable: the generated surface is `list`/`get` only and the
9
+ * service never updates an event after writing it.
10
+ */
1
11
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { SupportActorKind, SupportCaseEventType } from '../types.js';
12
+ import { type SupportActorKind, type SupportCaseEventType } from '../types.js';
3
13
  export declare class SupportCaseEvent extends SmrtObject {
4
14
  tenantId: string | null;
5
15
  caseId: string;
@@ -1,5 +1,16 @@
1
- import { DecisionRequest, DecisionResult, SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { SupportCaseStatus } from '../types.js';
1
+ /**
2
+ * SupportCase — the canonical, tenant-scoped record of a client support
3
+ * request (FR-28/FR-29): one Case per request across every channel, carrying
4
+ * priority, severity, plan snapshot, lifecycle state, assignment, resolution,
5
+ * and reopen history.
6
+ *
7
+ * Internal model — writes go through {@link SupportCaseService} (closed-facade
8
+ * idiom, mirroring `smrt-chat`'s `ChatService`). The generated CRUD surface is
9
+ * read-only (`list`/`get`); the save-time transition guard below additionally
10
+ * rejects illegal status flips done via raw field assignment.
11
+ */
12
+ import { type DecisionRequest, type DecisionResult, SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
13
+ import { type SupportCaseStatus } from '../types.js';
3
14
  /** Generate a short human-facing case number (unique enough per tenant). */
4
15
  export declare function generateCaseNumber(now?: Date): string;
5
16
  export declare class SupportCase extends SmrtObject {
@@ -1,5 +1,15 @@
1
+ /**
2
+ * SupportChannelBinding — marks a transport container (a chat room, an email
3
+ * account) as a Managed Support intake channel. Inbound activity on a bound
4
+ * container creates-or-joins Support Cases; unbound containers are never
5
+ * touched, so ordinary chat rooms and mailboxes stay out of the support
6
+ * system.
7
+ *
8
+ * Bindings are configuration (operator-managed), so unlike the case-side
9
+ * models they expose full generated CRUD.
10
+ */
1
11
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { SupportBindingKind, SupportChannelKind } from '../types.js';
12
+ import { type SupportBindingKind, type SupportChannelKind } from '../types.js';
3
13
  export declare class SupportChannelBinding extends SmrtObject {
4
14
  tenantId: string | null;
5
15
  /** Operator-facing binding name (inherited `name` is the display label). */
@@ -1,3 +1,14 @@
1
+ /**
2
+ * SupportCompensationPlan — the provider-facing **Support Compensation Plan**
3
+ * (FR-32/FR-35): the effective-dated terms under which a Support Specialist
4
+ * earns for delivered support time. Deliberately separate from
5
+ * {@link SupportPlan} (client pricing) so margin stays measurable and client
6
+ * terms never leak provider terms.
7
+ *
8
+ * Resolution: the specialist-specific plan effective at the work instant
9
+ * wins; otherwise the tenant default (`specialistId` null) effective at that
10
+ * instant applies.
11
+ */
1
12
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
13
  export declare class SupportCompensationPlan extends SmrtObject {
3
14
  tenantId: string | null;
@@ -1,5 +1,16 @@
1
+ /**
2
+ * SupportInteraction — a channel-neutral transport record attached to a
3
+ * Support Case (FR-28/FR-29): one row per message/chat/email/voice exchange,
4
+ * preserving chronology and transport metadata. The channel row (a
5
+ * `ChatMessage`, an `Email`, …) stays in its own package; this row links it
6
+ * via a qualified `sourceType`/`sourceId` pair and a globally unique
7
+ * `sourceKey` so re-ingesting the same transport record is idempotent.
8
+ *
9
+ * Internal model — writes go through {@link SupportCaseService}. Generated
10
+ * surface is read-only.
11
+ */
1
12
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { SupportActorKind, SupportChannelKind, SupportInteractionDirection } from '../types.js';
13
+ import { type SupportActorKind, type SupportChannelKind, type SupportInteractionDirection } from '../types.js';
3
14
  export declare class SupportInteraction extends SmrtObject {
4
15
  tenantId: string | null;
5
16
  caseId: string;
@@ -1,5 +1,23 @@
1
+ /**
2
+ * SupportPlan — the client-facing **Managed Support Plan** (FR-31): coverage
3
+ * hours and channels, severity definitions, acknowledgement / response /
4
+ * update / resolution Service Targets, pause rules, escalation policy, an
5
+ * availability fee, included support time, and metered overage pricing.
6
+ *
7
+ * Pure hourly support is a plan with zero availability fee and zero included
8
+ * minutes. A Service Target here is an operational objective — it becomes a
9
+ * contractual Service Level Agreement only in the governing agreement, which
10
+ * is out of this package's scope.
11
+ *
12
+ * Client pricing lives here; Support Specialist earnings live in the separate
13
+ * {@link SupportCompensationPlan} — the two are never merged (FR-32/FR-35).
14
+ *
15
+ * `subscriptionPlanKey` optionally binds the plan to a
16
+ * `@happyvertical/smrt-subscriptions` plan by its natural key for entitlement
17
+ * checks — a string reference, deliberately not a package dependency.
18
+ */
1
19
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { CoverageWindow, EscalationStep, ServiceTargetMinutes, SeverityDefinition, TimeApprovalPolicy } from '../types.js';
20
+ import { type CoverageWindow, type EscalationStep, type ServiceTargetMinutes, type SeverityDefinition, type TimeApprovalPolicy } from '../types.js';
3
21
  /** Default target minutes applied when a plan omits a severity's targets. */
4
22
  export declare const DEFAULT_TARGET_MINUTES: ServiceTargetMinutes;
5
23
  export declare class SupportPlan extends SmrtObject {
@@ -1,3 +1,14 @@
1
+ /**
2
+ * SupportPolicy — governs what the AI support workflow may do without a human
3
+ * (FR-28a/FR-28b): which phases run automatically, whether low-risk
4
+ * resolutions may complete autonomously, the confidence floor, sensitive
5
+ * categories, and the tool whitelist for troubleshooting.
6
+ *
7
+ * Resolution is most-specific-wins per case: `(planId, projectId)` exact →
8
+ * `planId` → `projectId` → tenant default (both null) → the package's
9
+ * conservative built-in defaults (see `DEFAULT_SUPPORT_POLICY`). Policies are
10
+ * operator configuration, so they expose full generated CRUD.
11
+ */
1
12
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
13
  /**
3
14
  * Conservative defaults applied when no SupportPolicy row matches: the AI
@@ -1,5 +1,19 @@
1
+ /**
2
+ * Service Target clocks and escalations (FR-30/FR-31).
3
+ *
4
+ * - **SupportServiceTarget** — one acknowledgement/response/update/resolution
5
+ * clock on a case, derived from the applicable plan's targets, coverage
6
+ * calendar, and pause rules. `escalationJobId` holds the one-shot
7
+ * `_smrt_jobs` row scheduled at `dueAt` so satisfying the target can cancel
8
+ * the pending escalation.
9
+ * - **SupportEscalation** — the auditable record of one escalation firing
10
+ * (target breach, target risk, manual, or AI-triggered).
11
+ *
12
+ * Both are written by the target engine / case service only; generated
13
+ * surfaces are read-only.
14
+ */
1
15
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { ServiceTargetStatus, ServiceTargetType, SupportEscalationReason } from '../types.js';
16
+ import { type ServiceTargetStatus, type ServiceTargetType, type SupportEscalationReason } from '../types.js';
3
17
  /** Outcome of one {@link SupportServiceTarget.checkAndEscalate} delivery. */
4
18
  export interface CheckAndEscalateResult {
5
19
  outcome: 'breached' | 'escalated' | 'rescheduled' | 'noop' | 'missing';
@@ -1,5 +1,24 @@
1
+ /**
2
+ * Derived commercial snapshots for approved Service Time Entries
3
+ * (FR-32/FR-35, issue #1930). Two deliberately separate rows per entry:
4
+ *
5
+ * - **SupportCharge** — what the Client owes, derived from the Managed
6
+ * Support Plan (included-time consumption, then metered overage).
7
+ * - **SupportCompensation** — what the delivering Participant earns, derived
8
+ * from the Support Compensation Plan.
9
+ *
10
+ * Margin = charge − compensation, computed by readers; the two records are
11
+ * never merged so client pricing can't leak provider terms. Rows snapshot the
12
+ * rate terms at derivation time (`rateSnapshot`) — later plan edits never
13
+ * rewrite them; corrections void/supersede and re-derive from the correcting
14
+ * entry. Settlement (invoicing, ledger posting) is out of scope here and
15
+ * composes at the app/accounting boundary (#1925).
16
+ *
17
+ * Append-only surfaces: `list`/`get` generated routes only; writes go through
18
+ * `TimeEntryApprovalService`.
19
+ */
1
20
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { SupportSettlementStatus } from '../types.js';
21
+ import { type SupportSettlementStatus } from '../types.js';
3
22
  export declare class SupportCharge extends SmrtObject {
4
23
  tenantId: string | null;
5
24
  timeEntryId: string;
@@ -1,5 +1,19 @@
1
+ /**
2
+ * Support Specialist models (FR-30): the specialist role record layered on a
3
+ * Profile (the `commerce Customer` role-record idiom), per-project
4
+ * qualifications, and availability/on-call windows.
5
+ *
6
+ * - **SupportSpecialist** — a Participant qualified to handle first-tier
7
+ * support; workload cap, languages, and timezone drive routing.
8
+ * - **SupportQualification** — recognition that a specialist is trained and
9
+ * approved for a specific app-defined project (effective-dated).
10
+ * - **SupportAvailability** — weekly working windows, on-call spans, and
11
+ * time-off exceptions used by routing and coverage checks.
12
+ *
13
+ * These are operator configuration surfaces, so they expose generated CRUD.
14
+ */
1
15
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { SupportAvailabilityKind, SupportQualificationLevel, SupportSpecialistStatus } from '../types.js';
16
+ import { type SupportAvailabilityKind, type SupportQualificationLevel, type SupportSpecialistStatus } from '../types.js';
3
17
  export declare class SupportSpecialist extends SmrtObject {
4
18
  tenantId: string | null;
5
19
  /** The Participant (Person profile) this specialist role belongs to. */
@@ -1,5 +1,17 @@
1
+ /**
2
+ * SupportWorkLink — links a Support Case to separately tracked internal work
3
+ * (FR-29/FR-29a): a **Support Work Item** on the operational board, or a
4
+ * **Development Work Item** created through a Delivery Handoff.
5
+ *
6
+ * Boundary: Support owns the Case and this link; Delivery Operations owns the
7
+ * linked work's execution (agents, previews, merges, deployments). The
8
+ * `status` field here is a read-only echo the delivery side reports back —
9
+ * this package never drives the linked item's lifecycle. Targets are
10
+ * addressed by qualified type + id (e.g. `@happyvertical/smrt-projects:Issue`)
11
+ * so no runtime dependency on the owning package is needed.
12
+ */
1
13
  import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
- import { SupportWorkLinkKind } from '../types.js';
14
+ import { type SupportWorkLinkKind } from '../types.js';
3
15
  export declare class SupportWorkLink extends SmrtObject {
4
16
  tenantId: string | null;
5
17
  caseId: string;
@@ -1,4 +1,15 @@
1
- import { PermissionDefinition } from '@happyvertical/smrt-users';
1
+ /**
2
+ * Custom permission slugs contributed by `@happyvertical/smrt-support` to the
3
+ * runtime permission catalog (the `personas.activate-directive` pattern).
4
+ *
5
+ * The privileged operations are permission splits, not bespoke checks:
6
+ * - `support.reassign-case` — manual reassignment despite routing (FR-30).
7
+ * - `support.approve-time-entry` — accept a Service Time Entry and derive its
8
+ * commercial snapshots (FR-36) via the operator path.
9
+ * - `support.manage-plans` — administer Managed Support Plans and Support
10
+ * Compensation Plans.
11
+ */
12
+ import { type PermissionDefinition } from '@happyvertical/smrt-users';
2
13
  /** Authorizes manual case reassignment overriding automatic routing. */
3
14
  export declare const REASSIGN_CASE_PERMISSION = "support.reassign-case";
4
15
  /** Authorizes operator approval/rejection of Service Time Entries. */
@@ -1,4 +1,25 @@
1
- import { CoverageWindow } from '../types.js';
1
+ /**
2
+ * Coverage-calendar math for Service Target clocks (FR-30/FR-31): pure,
3
+ * deterministic business-time arithmetic over a Managed Support Plan's
4
+ * coverage windows, holidays, and IANA timezone.
5
+ *
6
+ * Semantics:
7
+ * - An empty `windows` array means 24×7 coverage; with no holidays either,
8
+ * covered time is plain wall-clock time (the fast path).
9
+ * - Holidays (`YYYY-MM-DD` in the calendar's timezone) exclude whole days
10
+ * from coverage, including under 24×7 coverage.
11
+ * - All functions take explicit instants — no `Date.now()` inside — so the
12
+ * engine and its tests stay deterministic.
13
+ *
14
+ * Timezone handling uses `Intl.DateTimeFormat#formatToParts` only (no date
15
+ * library): {@link zonedParts} projects a UTC instant onto the calendar
16
+ * timezone's wall clock, and an iterative inverse converts wall-clock day
17
+ * positions back to UTC instants. DST transition days therefore keep exact
18
+ * window boundaries; a window boundary falling inside a nonexistent
19
+ * spring-forward hour lands on the later real instant so clocks never gain
20
+ * time.
21
+ */
22
+ import type { CoverageWindow } from '../types.js';
2
23
  /** The coverage terms a Service Target clock runs against. */
3
24
  export interface CoverageCalendar {
4
25
  /** Weekly coverage windows; empty means 24×7 coverage. */
@@ -1,7 +1,22 @@
1
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
1
+ /**
2
+ * HumanHandoffService — the lossless Human Handoff (FR-28b, issue #1928).
3
+ * Whatever pulls the trigger (an explicit client request, low answer
4
+ * confidence, a sensitive classification, high severity, failed automation,
5
+ * a policy cap, or a manual escalation), the handoff transfers the FULL case
6
+ * context — current state, the merged interaction/event timeline, and every
7
+ * prior {@link SupportAiRun} — so the Client never repeats themselves and the
8
+ * Support Specialist starts with the complete history.
9
+ *
10
+ * A no-repeat guarantee keeps at most one handoff active per case
11
+ * (`metadata.activeHandoff`): repeat triggers while one is pending only
12
+ * append a deduped audit event. Routing is a seam — the #1929 routing
13
+ * service plugs in via `assignSpecialist`; without it the case is queued for
14
+ * manual pickup (`new` → `triaged`).
15
+ */
16
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
17
  import { SupportAiRunCollection } from '../models/support-ai-run.js';
3
- import { SupportCase } from '../models/support-case.js';
4
- import { HumanHandoffTrigger } from '../types.js';
18
+ import type { SupportCase } from '../models/support-case.js';
19
+ import type { HumanHandoffTrigger } from '../types.js';
5
20
  import { SupportCaseService } from './support-case-service.js';
6
21
  /** One compact timeline entry inside a {@link HandoffContextPackage}. */
7
22
  export interface HandoffTimelineItem {
@@ -1,5 +1,5 @@
1
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
- import { AssistanceSupportPort } from '@happyvertical/smrt-projects';
1
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
+ import type { AssistanceSupportPort } from '@happyvertical/smrt-projects';
3
3
  import { SupportCaseService } from './support-case-service.js';
4
4
  /** Concrete lossless bridge from smrt-projects Assistance Requests to Support. */
5
5
  export declare class ProjectAssistanceSupportAdapter implements AssistanceSupportPort {
@@ -1,10 +1,37 @@
1
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
1
+ /**
2
+ * ServiceTargetEngine — Service Target clocks with timed escalation
3
+ * (FR-30/FR-31).
4
+ *
5
+ * Owns the full clock lifecycle on a case:
6
+ * - **start** — one clock per configured target type from the case's plan
7
+ * terms (the frozen `planSnapshot` wins over the live plan; sensible
8
+ * defaults with no plan), `dueAt` computed in *covered* time through the
9
+ * plan's coverage calendar, plus a one-shot `_smrt_jobs` row
10
+ * (`SupportServiceTarget.checkAndEscalate`) scheduled at `dueAt`;
11
+ * - **satisfy** — outbound specialist/agent interactions satisfy the
12
+ * acknowledgement/response clocks and roll the recurring update clock to
13
+ * its next cycle; satisfied clocks cancel their escalation job;
14
+ * - **pause/resume** — case statuses listed in the plan's `pauseStatuses`
15
+ * freeze clocks (FR-29b: waiting periods pause clocks *only when the plan
16
+ * says so*); resume recomputes `dueAt` from the remaining covered minutes
17
+ * and enqueues a fresh job;
18
+ * - **resolve/reopen** — resolution satisfies the resolution clock and
19
+ * cancels the rest; reopening starts fresh clocks on a new cycle;
20
+ * - **breach** — an overdue clock is marked breached and escalated through
21
+ * the plan's escalation policy (notify or reassign via
22
+ * {@link SupportRoutingService}), with optional delayed follow-up steps.
23
+ *
24
+ * The engine is invoked by the application around
25
+ * {@link SupportCaseService} calls; it deliberately takes explicit `at`
26
+ * instants so behavior is deterministic and testable.
27
+ */
28
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
29
  import { SmrtJobCollection } from '@happyvertical/smrt-jobs';
3
- import { SupportCase } from '../models/support-case.js';
4
- import { SupportInteraction } from '../models/support-interaction.js';
5
- import { SupportEscalationCollection, SupportServiceTarget, SupportServiceTargetCollection } from '../models/support-service-target.js';
6
- import { EscalationStep, ServiceTargetMinutes, SupportCaseStatus } from '../types.js';
7
- import { CoverageCalendar } from './coverage-calendar.js';
30
+ import type { SupportCase } from '../models/support-case.js';
31
+ import type { SupportInteraction } from '../models/support-interaction.js';
32
+ import { SupportEscalationCollection, type SupportServiceTarget, SupportServiceTargetCollection } from '../models/support-service-target.js';
33
+ import { type EscalationStep, type ServiceTargetMinutes, type SupportCaseStatus } from '../types.js';
34
+ import { type CoverageCalendar } from './coverage-calendar.js';
8
35
  import { SupportCaseService } from './support-case-service.js';
9
36
  /** Queue name for support escalation jobs. */
10
37
  export declare const SUPPORT_JOB_QUEUE = "support";
@@ -1,6 +1,18 @@
1
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
- import { ServiceTimeEntry, ServiceTimeEntryCollection } from '../models/service-time-entry.js';
3
- import { ServiceTimeEntrySource, SupportParticipantKind, TimeEntryEvidence } from '../types.js';
1
+ /**
2
+ * ServiceTimeEntryService — the shared recording contract for Service Time
3
+ * Entries (FR-40, issue #1930): timer, manual, imported, and automatic agent
4
+ * entries all pass ONE validation and audit gate, so no source can smuggle in
5
+ * an incoherent duration, participant, or work context.
6
+ *
7
+ * Recording is deliberately money-free: entries capture the work (duration,
8
+ * period, evidence, participant, context) and land as `draft`; pricing and
9
+ * earnings derive later, at approval time, in `TimeEntryApprovalService`.
10
+ * Case-attached entries append a `time_recorded` audit event so the case
11
+ * timeline shows the work as it happens.
12
+ */
13
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
14
+ import { type ServiceTimeEntry, ServiceTimeEntryCollection } from '../models/service-time-entry.js';
15
+ import type { ServiceTimeEntrySource, SupportParticipantKind, TimeEntryEvidence } from '../types.js';
4
16
  import { SupportCaseService } from './support-case-service.js';
5
17
  /** Options for {@link ServiceTimeEntryService.create}. */
6
18
  export interface ServiceTimeEntryServiceOptions extends SmrtObjectOptions {
@@ -1,12 +1,29 @@
1
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
- import { SupportAiRun, SupportAiRunCollection } from '../models/support-ai-run.js';
3
- import { SupportCase } from '../models/support-case.js';
1
+ /**
2
+ * SupportAiWorkflow — the Automated Support Response pipeline (FR-28a, issue
3
+ * #1928): on intake a case is immediately acknowledged, classified, and
4
+ * answered from scoped knowledge; only when the resolved {@link SupportPolicy}
5
+ * explicitly allows it may the workflow resolve a low-risk case autonomously.
6
+ * Every phase — run or skipped — writes an append-only {@link SupportAiRun}
7
+ * audit row, and every risk signal (client request, low confidence,
8
+ * sensitivity, high severity, boundary failure, attempt cap) routes through
9
+ * {@link HumanHandoffService} so a Support Specialist takes over with the
10
+ * complete context (FR-28b).
11
+ *
12
+ * The AI call is an injected {@link SupportAiBoundary} and knowledge
13
+ * retrieval an injected {@link SupportKnowledgeProvider} (the `smrt-personas`
14
+ * `ReflectionRunner` injected-boundary idiom) — tests mock only these seams,
15
+ * and the package stays dependency-free: apps plug `smrt-facts` /
16
+ * `smrt-content`-backed providers.
17
+ */
18
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
19
+ import { type SupportAiRun, SupportAiRunCollection } from '../models/support-ai-run.js';
20
+ import type { SupportCase } from '../models/support-case.js';
4
21
  import { SupportInteractionCollection } from '../models/support-interaction.js';
5
22
  import { SupportPolicyCollection } from '../models/support-policy.js';
6
- import { HumanHandoffTrigger, SeverityDefinition } from '../types.js';
23
+ import { type HumanHandoffTrigger, type SeverityDefinition } from '../types.js';
7
24
  import { HumanHandoffService } from './human-handoff-service.js';
8
25
  import { SupportCaseService } from './support-case-service.js';
9
- import { IntakeResult } from './support-intake-service.js';
26
+ import type { IntakeResult } from './support-intake-service.js';
10
27
  /** One knowledge source consulted while drafting an automated answer. */
11
28
  export interface KnowledgeSnippet {
12
29
  /** Source kind, e.g. `fact`, `article`, `document`. */
@@ -1,10 +1,18 @@
1
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
- import { SupportCase, SupportCaseCollection } from '../models/support-case.js';
3
- import { SupportCaseEvent, SupportCaseEventCollection } from '../models/support-case-event.js';
4
- import { SupportInteraction, SupportInteractionCollection } from '../models/support-interaction.js';
5
- import { SupportPlan, SupportPlanCollection } from '../models/support-plan.js';
6
- import { SupportWorkLink, SupportWorkLinkCollection } from '../models/support-work-link.js';
7
- import { SupportActorKind, SupportCaseEventType, SupportCaseStatus, SupportChannelKind, SupportInteractionDirection, SupportWorkLinkKind } from '../types.js';
1
+ /**
2
+ * SupportCaseService — the closed write facade for Support Cases (the
3
+ * `smrt-chat` `ChatService` idiom): case creation, interaction recording,
4
+ * lifecycle transitions, assignment, resolution, reopening, human requests,
5
+ * and work links all flow through here so the audit trail
6
+ * ({@link SupportCaseEvent}) and the lifecycle guard stay coherent. The
7
+ * generated CRUD surface on the case-side models is read-only.
8
+ */
9
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
10
+ import { type SupportCase, SupportCaseCollection } from '../models/support-case.js';
11
+ import { type SupportCaseEvent, SupportCaseEventCollection } from '../models/support-case-event.js';
12
+ import { type SupportInteraction, SupportInteractionCollection } from '../models/support-interaction.js';
13
+ import { type SupportPlan, SupportPlanCollection } from '../models/support-plan.js';
14
+ import { type SupportWorkLink, SupportWorkLinkCollection } from '../models/support-work-link.js';
15
+ import type { SupportActorKind, SupportCaseEventType, SupportCaseStatus, SupportChannelKind, SupportInteractionDirection, SupportWorkLinkKind } from '../types.js';
8
16
  export interface OpenCaseInput {
9
17
  tenantId?: string | null;
10
18
  subject: string;
@@ -1,7 +1,28 @@
1
- import { SmrtObject, SmrtObjectOptions } from '@happyvertical/smrt-core';
2
- import { SupportCase } from '../models/support-case.js';
3
- import { SupportChannelBinding, SupportChannelBindingCollection } from '../models/support-channel-binding.js';
4
- import { SupportInteraction } from '../models/support-interaction.js';
1
+ /**
2
+ * SupportIntakeService — channel intake: every inbound interaction on a bound
3
+ * transport container deterministically creates or joins one canonical
4
+ * Support Case (FR-28, issue #1926).
5
+ *
6
+ * Channels are transports, not systems of record: the ChatMessage / Email row
7
+ * stays canonical in its package; intake links it as a
8
+ * {@link SupportInteraction} (idempotent on `sourceKey`) and drives the
9
+ * create-or-join decision by conversation key:
10
+ *
11
+ * - chat: `chat:<roomId>[:<threadId>]` — a bound room is one client
12
+ * conversation; threads open distinct cases.
13
+ * - email: the RFC thread — a reply (`inReplyTo`) joins the case holding the
14
+ * referenced message; otherwise the message id starts a new thread key.
15
+ *
16
+ * Join semantics: open case → join; resolved case → reopen + join (the client
17
+ * replied to a "resolved" conversation); closed case → a fresh case.
18
+ *
19
+ * Intake never throws into the source package's save path — the opt-in
20
+ * interceptor (`registerSupportIntake`) swallows and logs intake errors.
21
+ */
22
+ import type { SmrtObject, SmrtObjectOptions } from '@happyvertical/smrt-core';
23
+ import type { SupportCase } from '../models/support-case.js';
24
+ import { type SupportChannelBinding, SupportChannelBindingCollection } from '../models/support-channel-binding.js';
25
+ import type { SupportInteraction } from '../models/support-interaction.js';
5
26
  import { SupportCaseService } from './support-case-service.js';
6
27
  /** Qualified source types intake understands. */
7
28
  export declare const CHAT_MESSAGE_SOURCE_TYPE = "@happyvertical/smrt-chat:ChatMessage";
@@ -1,7 +1,20 @@
1
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
- import { SupportCompensationPlan, SupportCompensationPlanCollection } from '../models/support-compensation-plan.js';
3
- import { SupportPlan, SupportPlanCollection } from '../models/support-plan.js';
4
- import { SupportPrincipal } from '../permissions.js';
1
+ /**
2
+ * SupportPlanAdminService — the permission-gated write surface for
3
+ * commercial terms: Managed Support Plans (client pricing/service terms) and
4
+ * Support Compensation Plans (provider earning terms).
5
+ *
6
+ * The `support.manage-plans` split is the gate (the
7
+ * `personas.activate-directive` idiom): the generated CRUD routes on both
8
+ * models are read-only, so every plan write flows through here, carries an
9
+ * accountable principal, and refuses cross-tenant acts. Plan history stays
10
+ * safe regardless — cases snapshot plan terms at apply time and settlements
11
+ * snapshot rates at approval time — but only holders of the split may shape
12
+ * future terms.
13
+ */
14
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
15
+ import { type SupportCompensationPlan, SupportCompensationPlanCollection } from '../models/support-compensation-plan.js';
16
+ import { type SupportPlan, SupportPlanCollection } from '../models/support-plan.js';
17
+ import { type SupportPrincipal } from '../permissions.js';
5
18
  /** Thrown when a plan write is attempted without the manage-plans split. */
6
19
  export declare class PlanAdminDeniedError extends Error {
7
20
  constructor(message: string);
@@ -1,8 +1,23 @@
1
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
- import { SupportCase } from '../models/support-case.js';
1
+ /**
2
+ * SupportRoutingService — Project-qualified Support Case routing (FR-30).
3
+ *
4
+ * Ranks Support Specialists for a case with an **explainable** score: every
5
+ * hard eligibility check (active status, effective Project Support
6
+ * Qualification, workload cap, availability) is recorded as a factor on the
7
+ * ranked entry, so the queue UI can show *why* someone was or wasn't chosen.
8
+ * Ineligible specialists stay in the returned ranking (`eligible: false`)
9
+ * for that rationale display.
10
+ *
11
+ * `autoAssign` writes the assignment through {@link SupportCaseService} with
12
+ * the ranking rationale in the audit event; `reassign` is the manual
13
+ * override, gated by the `support.reassign-case` permission split and a
14
+ * cross-tenant guard.
15
+ */
16
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
17
+ import type { SupportCase } from '../models/support-case.js';
3
18
  import { SupportAvailabilityCollection, SupportQualificationCollection, SupportSpecialistCollection } from '../models/support-specialist.js';
4
- import { SupportPrincipal } from '../permissions.js';
5
- import { SupportActorKind } from '../types.js';
19
+ import { type SupportPrincipal } from '../permissions.js';
20
+ import type { SupportActorKind } from '../types.js';
6
21
  import { SupportCaseService } from './support-case-service.js';
7
22
  /**
8
23
  * Named scoring weights, so the ranking is auditable against the code.