/** * Two-tier SIEM dependency scan for a ladder plan. * * The persona reviews' top blocker was "the plan says WHAT, never what it * TOUCHES". A naive literal scan is half theater: real monitors reference * SLICES (service:payment status:error), not message templates, so literal * absence is not safety — and slice overlap is too broad to exclude on * (every payment monitor overlaps every payment type). Hence two tiers: * * TIER 1 — LITERAL: an object's query/title contains the type's distinctive * tokens. High precision. These types are EXCLUDED from the plan by default * (pinned at pass, plan re-solved) unless the user trades them back in. * * TIER 2 — SLICE: objects whose text mentions a planned service at all. * High recall, deliberately broad. A DISCLOSURE, never an exclusion — * rendered with the destination's platform truth (Flex data and real-time * monitors, the IA class and metric filters, offload and every query). * * The vendor inventory is fetched ONCE (lib/siem/deps fetchVendorInventory) * and matched locally, so a 200-type plan costs the same API calls as one. * Scan-depth honesty rides on the summary: what was scanned is stated, and * "no literal references found in what was scanned" is the strongest claim * the data supports — never "safe". */ import type { Plan, PlannedRow, SolverPattern, SolveOpts } from './plan-solver.js'; import type { SiemId } from './siem/pricing.js'; import { fetchVendorInventory as realFetchVendorInventory, type VendorInventory } from './siem/deps/index.js'; export interface PlanRowDependencies { hash: string; name: string; displayName: string; refs: number; /** Names of the referencing objects (monitors/searches/dashboards), capped at 5. */ names: string[]; /** Savings this row carried in the ORIGINAL solve — what excluding it forgoes. */ forgoneUsd: number; } export interface SliceDependency { service: string; objects: number; /** Referencing-object names, capped at 5. */ names: string[]; } export interface PlanDependencySummary { /** True when a scan actually ran (credentials present, vendor supported). */ checked: boolean; vendor?: SiemId; /** What the scan could actually see, e.g. "monitor queries and dashboard * titles/descriptions". The honesty line: absence of literal hits means * "none found in THIS", never "safe". */ scan_depth?: string; /** How many planned rows were matched (all of them — batch inventory). */ scanned_rows: number; /** TIER 1: planned types literally referenced by name/query text. */ literal: PlanRowDependencies[]; /** TIER 1 outcome: types excluded from the final plan (pinned at pass). */ excluded: PlanRowDependencies[]; /** TIER 2: objects that mention a planned service at all — disclosure only. */ slice: SliceDependency[]; /** Destination truth for the levers in play, stated once. */ platform_truth?: string; total_refs: number; /** One human-readable line: what ran, or why nothing did. Render-safe. */ note: string; } /** Map a plan destination onto the dep-check vendor that can scan it. */ export declare function depVendorForDestination(destination: SiemId): SiemId | null; /** Instant, env-only credential preflight per dep-check vendor. */ export declare function depCredsPresent(vendor: SiemId): { present: boolean; missing: string; }; type InventoryFetcher = typeof realFetchVendorInventory; /** Test seam, same pattern as _setBackendLoader / _setVerifyRunner. */ export declare function _setInventoryFetcher(fn: InventoryFetcher): void; export declare function _resetInventoryFetcher(): void; /** Destination truth for the levers a plan actually uses. */ export declare function platformTruth(plan: Plan): string | undefined; /** TIER 2: which inventory objects mention each planned service at all. */ export declare function sliceScan(inv: VendorInventory, services: string[]): SliceDependency[]; export interface CheckPlanDepsOptions { /** Overall wall-clock budget for the inventory fetch. Default 20000ms. */ timeoutMs?: number; } export declare function checkPlanDependencies(plan: Plan, opts?: CheckPlanDepsOptions): Promise; /** * TIER 1 outcome: pin the literally-referenced types at pass and re-solve. * Pure given the summary — the caller passes the same patterns/opts it solved * with. Returns the re-solved plan and the exclusion record for the render; * the excluded rows carry the savings the exclusion forgoes. */ export declare function applyReferencedExclusion(patterns: SolverPattern[], solveOpts: SolveOpts, summary: PlanDependencySummary): { plan: Plan; excluded: PlanRowDependencies[]; }; export type { PlannedRow };