hiphopsllm.faulttree¶
Fault trees: local failure logic, compositional synthesis, and analysis.
Three HiP-HOPS phases live here.
Annotate (failure) — every component is given an IF-FMEA table:
each output deviation is a Boolean expression over the component’s input
deviations and its own internal basic events. The library covers the agentic
archetypes: LLM agent, tool/executor, router, aggregator, transform, boundary
and feedback cut.
Synthesise (synthesis) — a tree is produced by traversing
connections backwards from a system-level hazard and substituting each
component’s local logic, memoised so shared sub-trees stay shared (HiP-HOPS
transfer gates). Trees are never drawn by hand.
Analyse (analysis) — minimal cut sets by MOCUS with absorption,
quantification by the minimal cut upper bound, Birnbaum and Fussell-Vesely
importance, single points of failure, and a generated FMEA table.
The deviation notation is HiP-HOPS’ own, class-component.port:
O-coder.out, VS-aggregator.out. The six failure classes are in
FClass; keeping VC (coarse, detectable) apart from VS (subtle,
plausible — the hallucination case) is the single most important modelling
decision in the library, because they propagate identically but one is caught at
the system boundary and the other is delivered to the user.
Failure logic¶
hiphopsllm.faulttree.failure — deviations, Boolean failure expressions and the annotation library (HiP-HOPS Phase 1: “annotate components with local failure logic”).
In HiP-HOPS every component carries an IF-FMEA table: for each output deviation of the component, a logical expression over input deviations and internal basic events that explains how that output deviation arises. Fault trees are never drawn by hand — they are synthesised by composing these local tables along the architecture’s connections.
Deviation notation follows the HiP-HOPS convention <class>-<component>.<port>:
O-coder.out omission of the tool's output
VS-generator.out subtle (plausible but wrong) value deviation
Failure classes are the classical guideword set, specialised for LLM-based agents. The distinction that matters most for agentic systems is between VALUE_COARSE (wrong and detectable — malformed, unparsable, schema violation) and VALUE_SUBTLE (wrong but plausible — the hallucination case, which no downstream syntactic check will catch). They have very different propagation behaviour and very different consequences, so they are kept apart throughout.
- class hiphopsllm.faulttree.failure.FClass[source]¶
-
Deviation guidewords used by the annotation library.
- OMISSION = 'O'¶
- COMMISSION = 'C'¶
- VALUE_COARSE = 'VC'¶
- VALUE_SUBTLE = 'VS'¶
- EARLY = 'E'¶
- LATE = 'L'¶
- property title: str¶
Return a version of the string where each word is titlecased.
More specifically, words start with uppercased characters and all remaining cased characters have lower case.
- __new__(value)¶
- class hiphopsllm.faulttree.failure.Deviation[source]¶
Bases:
objectA failure of class
fclassobserved atcomponent.port.
- class hiphopsllm.faulttree.failure.Expr[source]¶
Bases:
objectBase class of the local failure-logic expression language.
- class hiphopsllm.faulttree.failure.BasicEventRef[source]¶
Bases:
ExprReference to an internal basic event (a leaf of the fault tree).
- class hiphopsllm.faulttree.failure.DevRef[source]¶
Bases:
ExprReference to a deviation at one of this component’s ports.
- hiphopsllm.faulttree.failure.AND(*terms)[source]¶
Build a simplified conjunction (flattens, drops TRUE, dedups).
- hiphopsllm.faulttree.failure.OR(*terms)[source]¶
Build a simplified disjunction (flattens, drops FALSE, dedups).
- class hiphopsllm.faulttree.failure.BasicEvent[source]¶
Bases:
objectA leaf failure: an internal fault of one component, or a shared cause.
probis the point estimate used for quantification.prob_intervaloptionally carries an imprecise (lower, upper) pair — useful when the estimate comes from a small sample, which is the normal situation for LLM failure rates.-
baseline_prob:
Optional[float] = None¶ The probability this event had before any calibration touched it, set once by the calibrator. Calibration splits a component’s measured probability over its events in proportion to their priors; without a stable baseline the second calibration would use the first one’s output as weights and quietly move numbers that were already measured.
- __init__(id, component, label, fclass, prob=0.05, prob_interval=None, baseline_prob=None, kind='internal', rationale='', mitigation='', evidence='engineering judgement (placeholder — replace with measurement)')¶
-
baseline_prob:
- class hiphopsllm.faulttree.failure.ComponentFailureLogic[source]¶
Bases:
objectThe IF-FMEA table of one component.
-
logic:
Dict[Deviation,Expr]¶ output deviation -> Boolean expression over input deviations + basic events
-
events:
Dict[str,BasicEvent]¶
- add_event(event)[source]¶
- Return type:
- Parameters:
event (BasicEvent)
-
logic:
- class hiphopsllm.faulttree.failure.FailureModel[source]¶
Bases:
objectThe annotated system: architecture + per-component failure logic.
-
system:
SystemModel¶
-
logic:
Dict[str,ComponentFailureLogic]¶
-
events:
Dict[str,BasicEvent]¶
- __init__(system, logic=<factory>, events=<factory>, ccf_groups=<factory>, connection_events=<factory>, notes=<factory>)¶
-
system:
- hiphopsllm.faulttree.failure.annotate_system(system, probability_overrides=None, entropy_by_component=None, extra_logic=None)[source]¶
Annotate every component with its local failure logic (HiP-HOPS Phase 1).
- Parameters:
entropy_by_component (
Optional[Dict[str,float]]) – Measured semantic-cluster entropy per component (from the notebook’suncertainty_summary). Where present it replaces the placeholder probability of that component’s hallucination / non-determinism events throughentropy_to_fail_prob().system (SystemModel)
extra_logic (Dict[str, ComponentFailureLogic] | None)
- Return type:
- hiphopsllm.faulttree.failure.entropy_to_fail_prob(entropy_value, ent_mid=0.9, slope=3.0, p_min=0.01, p_max=0.95)[source]¶
Map semantic-cluster entropy to a failure probability.
Identical calibration to the Bayesian-network cell of the source notebook, so the fault tree and the BN are quantified on the same scale. Entropy is computed by
HFSemanticUncertaintyover K resamples of one prompt: high entropy means the agent’s answer is unstable, which we read as an elevated probability of a subtle value deviation.
Synthesis¶
hiphopsllm.faulttree.synthesis — fault tree synthesis (HiP-HOPS Phase 2).
HiP-HOPS does not ask the analyst to draw fault trees. It synthesises them: starting from a system-level hazard expressed as a deviation at the system boundary, it walks the architecture backwards, and at each component substitutes the local failure expression for the deviation being explained. Input deviations are resolved across connections into output deviations of the upstream component, and the traversal continues until only basic events remain.
The same happens here, over the acyclic projection of the agent graph:
hazard H2 "wrong answer delivered, undetected"
= VS-__end__.in
= VS-aggregator.out (across the connection)
= BE-aggregator-SELECT AND (VS-react.out OR VS-cot.out)
OR (VS-react.out AND VS-cot.out)
OR CCF-LLM-... (shared model snapshot)
= ... until every leaf is a basic event
Termination is structural, not heuristic: the architecture is acyclic before
synthesis starts, expansions only ever move upstream, and every deviation is
expanded at most once (the result is memoised and shared, exactly as a transfer
gate is shared in a hand-drawn tree). A defensive path check remains, so a
malformed annotation produces a clearly-labelled circular reference
undeveloped event instead of an infinite recursion.
- class hiphopsllm.faulttree.synthesis.FTNode[source]¶
Bases:
objectOne node of the synthesised tree.
ntypetop | intermediate | basic | undeveloped | housegateAND | OR | None (a single-cause pass-through)-
transfer_ref:
Optional[str] = None¶ transfer tag (“A”, “B”, …) linking a transfer symbol to its subtree
- __init__(id, ntype, label, gate=None, children=<factory>, deviation=None, event_id=None, component=None, port_kind=None, repeat_of=None, transfer_ref=None, detail='')¶
-
transfer_ref:
- class hiphopsllm.faulttree.synthesis.FaultTree[source]¶
Bases:
objectA synthesised static fault tree (a rooted DAG with shared sub-trees).
-
events:
Dict[str,BasicEvent]¶
- simplified(**kwargs)[source]¶
Return a structurally reduced copy (see
simplify_tree()).- Return type:
-
events:
- class hiphopsllm.faulttree.synthesis.Hazard[source]¶
Bases:
objectA system-level effect to be analysed, anchored to a boundary deviation.
- hiphopsllm.faulttree.synthesis.default_hazards(model)[source]¶
The standard hazard list for an agentic workflow.
Anchored at the system boundary (the sink’s input ports), plus one hazard per component that executes model-authored code, because that effect is not observable at the output port at all.
- Return type:
- Parameters:
model (SystemModel)
- hiphopsllm.faulttree.synthesis.synthesise_fault_tree(fmodel, hazard, simplify=True)[source]¶
Synthesise the fault tree for one hazard.
- Return type:
- Parameters:
fmodel (FailureModel)
hazard (Hazard)
simplify (bool)
- hiphopsllm.faulttree.synthesis.synthesise_all(fmodel, hazards=None, simplify=True)[source]¶
Synthesise one fault tree per hazard, keyed by hazard id.
- hiphopsllm.faulttree.synthesis.simplify_tree(tree, collapse_single_input=True, flatten_gates=True, flatten_ports=True, dedup_inputs=True)[source]¶
Reduce a synthesised tree to its informative structure.
Synthesis is deliberately literal: it emits one intermediate event per deviation, so a chain of components produces a chain of one-input gates. That is faithful but tedious to read, and a one-input OR is not a gate at all. Three reductions are applied to a fixed point:
- Return type:
- Parameters:
collapse_single_inputA gate with a single input is that input.
OR(BE-coder-PARSE)becomesBE-coder-PARSEand the intervening event box disappears.flatten_gatesOR(a, OR(b, c))becomesOR(a, b, c)for the anonymous combination gates.flatten_portsAn input-port deviation is absorbed into the output deviation it causes: “omission at coder.in” under “omission of coder.out” is one step, not two. One node per component output survives, so the propagation between components stays visible while the port-level bookkeeping goes. Set
Falseto keep every port explicitly.dedup_inputsThe same input listed twice under one gate is listed once.
The Boolean function is unchanged: every reduction is an identity of Boolean algebra, so the minimal cut sets before and after are identical.
test_synthesis_internals.pychecks exactly that. The unreduced tree remains available (report.raw_trees) when the full propagation chain is wanted.
- hiphopsllm.faulttree.synthesis.describe_deviation(system, dev)[source]¶
- Return type:
- Parameters:
system (SystemModel)
dev (Deviation)
Analysis¶
hiphopsllm.faulttree.analysis — minimal cut sets, quantification and FMEA (HiP-HOPS Phase 3: “analyse the synthesised trees”).
Three products are derived from each synthesised tree:
Minimal cut sets. The smallest combinations of basic events that are together sufficient to cause the top event. Order-1 cut sets are single points of failure: one fault, one hazard, no redundancy in between. For agentic systems this is the number that matters — an architecture drawn with two “independent” agents and a judge looks redundant, and the cut sets say whether it actually is.
Quantification. Point probabilities per cut set, and a top-event estimate by
the minimal-cut upper bound. Where a basic event carries an imprecise
prob_interval the bound is evaluated at both ends, so the result is reported
as an interval rather than false precision. All defaults are placeholders and
are labelled as such; the value of the analysis is in the structure and the
ranking, which are unaffected by the absolute numbers.
FMEA. The inverse view: for each component failure mode, which hazards it causes, whether it causes them alone, and how much it contributes.
- class hiphopsllm.faulttree.analysis.CutSetResult[source]¶
Bases:
objectCutSetResult(sets: ‘List[CutSet]’ = <factory>, symbols: ‘Dict[str, BasicEvent]’ = <factory>, truncated: ‘bool’ = False, max_order: ‘int’ = 0, notes: ‘List[str]’ = <factory>)
-
symbols:
Dict[str,BasicEvent]¶
-
symbols:
- class hiphopsllm.faulttree.analysis.Quantification[source]¶
Bases:
objectQuantification(top_probability: ‘float’ = 0.0, top_interval: ‘Tuple[float, float]’ = (0.0, 0.0), rare_event_sum: ‘float’ = 0.0, cut_set_probability: ‘Dict[CutSet, float]’ = <factory>, method: ‘str’ = ‘minimal-cut upper bound (MCUB)’, imprecise: ‘bool’ = False, notes: ‘List[str]’ = <factory>)
- __init__(top_probability=0.0, top_interval=(0.0, 0.0), rare_event_sum=0.0, cut_set_probability=<factory>, method='minimal-cut upper bound (MCUB)', imprecise=False, notes=<factory>)¶
- hiphopsllm.faulttree.analysis.cut_sets(tree, fmodel=None, max_order=6, max_sets=20000)[source]¶
Compute the minimal cut sets of a synthesised tree (MOCUS, bottom-up).
max_orderandmax_setsbound the combinatorial expansion; truncation is always reported rather than silently applied, because an unreported truncation reads as “there is nothing else”, which would be false.- Return type:
- Parameters:
tree (FaultTree)
fmodel (FailureModel | None)
max_order (int)
max_sets (int)
- hiphopsllm.faulttree.analysis.quantify(result)[source]¶
Top-event probability by the minimal-cut upper bound, with intervals.
- Return type:
- Parameters:
result (CutSetResult)
- hiphopsllm.faulttree.analysis.importance(result, quant)[source]¶
Rank basic events by contribution to the top event.
Fussell-Vesely is the share of the (rare-event) top probability carried by cut sets containing the event; Birnbaum is the sensitivity of the top event to that event; risk reduction worth is the factor by which the top event would fall if the event were eliminated.
- Return type:
List[ImportanceRow]- Parameters:
result (CutSetResult)
quant (Quantification)
- hiphopsllm.faulttree.analysis.fmea_table(analyses)[source]¶
Derive the FMEA from the synthesised trees (the HiP-HOPS inversion step).
‘Direct effect’ means the failure mode causes the hazard on its own (an order-1 cut set); ‘further effect’ means it does so in combination with other failures. This is the classical HiP-HOPS FMEA, which is generated from the trees rather than elicited separately, so the two views cannot disagree.
- Return type:
List[FMEARow]- Parameters:
analyses (Dict[str, TreeAnalysis])
- hiphopsllm.faulttree.analysis.single_points_of_failure(analyses)[source]¶
Every (hazard, basic event) pair where one failure alone causes the hazard.
- hiphopsllm.faulttree.analysis.analyse_tree(tree, fmodel=None, max_order=6, max_sets=20000)[source]¶
- Return type:
- Parameters:
tree (FaultTree)
fmodel (FailureModel | None)
max_order (int)
max_sets (int)
- class hiphopsllm.faulttree.analysis.TreeAnalysis[source]¶
Bases:
objectTreeAnalysis(tree: ‘FaultTree’, cuts: ‘CutSetResult’, quant: ‘Quantification’, importance: ‘List[ImportanceRow]’)
-
cuts:
CutSetResult¶
-
quant:
Quantification¶
- __init__(tree, cuts, quant, importance)¶
- Parameters:
tree (FaultTree)
cuts (CutSetResult)
quant (Quantification)
importance (List[ImportanceRow])
- Return type:
None
-
cuts:
Export¶
Export of synthesised fault trees and reports.
to_mermaidFault tree as a mermaid flowchart — renders in a notebook the same way the LangGraph diagram does.
to_dotGraphviz DOT with conventional fault-tree shapes.
to_jsonMachine-readable tree, for diffing across releases.
to_openpsa_xmlOpen-PSA MEF, so the tree can be opened in an external fault-tree tool (XFTA, SCRAM) rather than trusted blindly.
markdown_reportThe full safety-analysis document, including the loop handling and the common-cause notes.
- hiphopsllm.faulttree.export.to_mermaid(tree, direction='TB', show_gate=True)[source]¶
Render the fault tree as mermaid text.
Gates are drawn as their own nodes between an event and its causes, which is as close to the conventional AND/OR symbols as mermaid gets; the matplotlib renderer (
hiphopsllm.viz.plots) draws the real symbols. Shared sub-trees (the equivalent of a transfer gate) appear once and are referenced by several parents, outlined so a shared cause is visible as such.
- hiphopsllm.faulttree.export.to_dot(tree)[source]¶
Graphviz DOT using conventional fault-tree shapes.
- hiphopsllm.faulttree.export.to_json(tree, analysis=None, indent=2)[source]¶
- Return type:
- Parameters:
tree (FaultTree)
analysis (TreeAnalysis | None)
indent (int)
- hiphopsllm.faulttree.export.to_openpsa_xml(tree, name=None)[source]¶
Export in Open-PSA Model Exchange Format for an external FT engine.
Being able to re-run the cut sets in an independent tool is the cheapest available check on this implementation, so the export is part of the normal output rather than an extra.
- hiphopsllm.faulttree.export.markdown_report(system, fmodel, analyses, cycle_report=None, title=None, include_trees=True)[source]¶
The full HiP-HOPS-style analysis document.
- Return type:
- Parameters:
system (SystemModel)
fmodel (FailureModel)
analyses (Dict[str, TreeAnalysis])
cycle_report (CycleReport | None)
title (str | None)
include_trees (bool)