/** * DELEGATION-TRIFECTA — the lethal trifecta SPLIT across a delegation edge. * * The per-unit {@link lethalTrifectaIssues} (`./lethal-trifecta.ts`) catches a * single subagent / skill that holds all THREE capability legs at once. But the * trifecta can EMERGE across a delegation (or inheritance) edge: a parent that * can only read private data (leg A) delegates to a child that can ingest * untrusted content AND exfiltrate (legs B+C). NEITHER unit trips the per-unit * check, yet the CHAIN — the parent plus everything it can reach — forms the full * trifecta. A prompt injection in the child's untrusted input can pivot back * through the delegation and leak the parent's private data. * * This is CAPABILITY-DIFF ACROSS THE DELEGATION TREE: the EFFECTIVE (combined) * capability of a unit is the union of its own tools plus the tools of every unit * reachable through `delegatesTo`. We classify that effective set and flag a unit * whose effective set is a full trifecta while its OWN set is not. * * NO DOUBLE-REPORT (one-detector-no-drift / don't-cry-wolf): a unit whose OWN * tools already form a full trifecta is SKIPPED here — {@link lethalTrifectaIssues} * owns it. This detector reports ONLY the EMERGENT case the per-unit check can't * see. * * HIGH-PRECISION (FP-safe): if the effective set contains a wildcard (inherits-all) * the unit reaches everything and would always "trifecta" — that maximal-blast- * radius case is the per-unit ADVISORY detector's job, so we SKIP it. We flag ONLY * concrete, explicit tool unions where every leg is supplied by a named tool. * * Pure, no IO. The delegation graph (nodes + directed `delegatesTo` edges) is the * INPUT — this module does not decide where edges come from; a caller supplies them * from the parsed harness. The dialect is injected (core ⊄ adapter), reused for the * underlying leg classification. */ import type { HarnessDialect } from "./dialect.js"; import { type TrifectaLegs } from "./lethal-trifecta.js"; /** One unit (subagent/skill) in the delegation graph. */ export interface CapabilityNode { readonly name: string; readonly kind: "skill" | "agent"; /** This unit's OWN declared tools. [] = none declared. ["*"] = inherits-all (wildcard). */ readonly tools: readonly string[]; /** Names of units this one can delegate to / inherits capabilities from (directed edges). */ readonly delegatesTo: readonly string[]; } /** A trifecta that EMERGES across delegation — present in a unit's effective set but NOT its own. */ export interface DelegationTrifectaFinding { readonly name: string; readonly kind: "skill" | "agent"; /** The delegated-to units (by name) that supplied at least one leg the unit lacks on its own. */ readonly via: readonly string[]; /** The tools that supplied each leg in the EFFECTIVE (combined) set. */ readonly legs: TrifectaLegs; /** Ready-to-show, actionable message. */ readonly message: string; } /** * Find units whose EFFECTIVE (own + delegated) capability set forms a full lethal * trifecta that their OWN set does not — an emergent, cross-delegation exfil path. * * Returns findings in stable order (by node name). See the module header for the * skip rules (own-set already a trifecta → owned by the per-unit detector; an * effective wildcard → owned by the per-unit advisory). */ export declare function delegationTrifectaIssues(nodes: readonly CapabilityNode[], dialect: HarnessDialect): DelegationTrifectaFinding[]; //# sourceMappingURL=delegation-trifecta.d.ts.map