Risk Management
Risk management identifies what may go wrong in a project, assesses how likely it is and how hard it would hit, and tracks the measures against it. A risk register collects the risks of a project: each with its probability, its impact, its state, the implications it has, if it occurs, and the mitigations reducing it.
Data Model
The risk management model of pyEDAA.Reports.RiskManagement is a risk register: the root,
RiskManagement, holds every risk, implication and mitigation by its ID. A risk
references its implications and mitigations, so several risks can share one.
A risk’s
Probabilitysays how likely it occurs: from low (identified, but sleeping) to occurred (the risk is active and causes heavy effects). ItsImpactsays how much delay it causes, if it occurs: from low (a few days) to critical (multiple weeks).A risk’s
Scoreis the rank of its probability times the rank of its impact, 1 to 16. The score classifies the risk by aRiskLevel- see the matrix below -, e.g. to iterate the critical risks.A risk’s
RiskStatefollows its life cycle: open or on hold while it is tracked; then either solved - its mitigations removed it - or closed - it isn’t tracked anymore, without being solved, e.g. because it was accepted or its time has passed.An
Implicationcan have implications of its own, and it can be mitigated like a risk.A
Mitigationcan have implications too: its side effects. So the same mitigation reduces a risk and a second-order implication, and its side effects are visible in the register.A risk’s second-order implications (
Risk.SecondOrderImplications) are the implications of its implications and the side effects of its mitigations.A mitigation’s
MitigationKindsays how it reduces a risk: it avoids its cause, prevents it - reduces its probability -, is a contingency plan applied, when the risk occurs, or transfers the impact to a third party. ItsMitigationStatesays whether it is applied: on hold - waiting to be planned -, planned, active, done or abandoned.A risk names its owner - the person responsible for it - and the date of its next review; a date without a time zone is a local time. The owner is a
Person- user ID, name, e-mail address -, which the register refers to (RiskManagement.AddPerson(),RiskManagement.Persons). The same person may be registered in several registers, e.g. a register of risks and a specification of requirements.A
Linkrelates two risks of the same register: from its source to its destination, of aLinkKind- e.g. causes, amplifies, depends on, duplicates. A link has no parent: both risks list it -Risk.OutboundLinksandRisk.InboundLinks-, and the register lists it inRiskManagement.Links. A source has at most one link of a kind to a destination.Risk.LinkTo()andRisk.LinkFrom()create an outbound or inbound link of a risk, with the parameters of the link’s constructor.An element joins the register by naming it as its parent, in its constructor or by
Parent. An ID is unique among the elements of its kind; a second element of the same ID raises a duplicate error of its kind, e.g.DuplicateRiskError- each aDuplicateElementErrorand aRiskManagementError. An element already part of a register raises anAlreadyInRiskRegisterError- anAlreadyInHierarchyError.An element of the register references only implications and mitigations of the same register, and a link connects risks of the same register: referenced elements and linked risks join the register first. Otherwise a
NotInSameRiskRegisterError- aNotInSameHierarchyError- is raised: the element is valid, but not part of the register. A risk’s owner is a person of the register too.Every element - the register too - has key-value pairs for data the model doesn’t name, e.g. a ticket:
risk["ticket"] = "#42".The register iterates its risks, implications, mitigations and links, optionally filtered by a predicate, e.g.
RiskManagement.IterateRisks().
Probability |
Impact low |
medium |
high |
critical |
|---|---|---|---|---|
low |
low (1) |
low (2) |
low (3) |
medium (4) |
medium |
low (2) |
medium (4) |
medium (6) |
high (8) |
high |
low (3) |
medium (6) |
high (9) |
critical (12) |
occurred |
medium (4) |
high (8) |
critical (12) |
critical (16) |
from pyTooling.Versioning import SemanticVersion
from pyEDAA.Reports import Person
from pyEDAA.Reports.RiskManagement import Impact, Implication, LinkKind, Mitigation, MitigationKind
from pyEDAA.Reports.RiskManagement import Probability, Risk, RiskLevel, RiskManagement
register = RiskManagement(SemanticVersion(1, 0, 0), "Wafer tape-out")
paebbels = Person("paebbels", "Patrick Lehmann", "paebbels@example.com")
register.AddPerson(paebbels)
budget = Implication("I3", "The budget rises.", parent=register)
shuttle = Mitigation("M1", "Order a second shuttle run.", [budget], MitigationKind.Contingency, parent=register)
launch = Implication("I2", "The product launch is delayed.", parent=register)
tapeOut = Implication("I1", "The tape-out is delayed.", implications=[launch], parent=register)
foundry = Risk(
"R1", "Late silicon", "The foundry delays the wafers.", Probability.High, Impact.High,
implications=[tapeOut], mitigations=[shuttle], owner=paebbels, parent=register
)
foundry["ticket"] = "#42"
board = Risk("R2", "Late board", "The board waits.", Probability.Medium, Impact.High, parent=register)
foundry.LinkTo(board, LinkKind.Causes)
for risk in register.IterateRisks(lambda risk: risk.Level in (RiskLevel.High, RiskLevel.Critical)):
causes = [link.Destination.ID for link in risk.OutboundLinks if link.Kind is LinkKind.Causes]
print(f"{risk.ID} {risk.Title} ({risk.Level}, owner {risk.Owner.Name}): causes {', '.join(causes)}")
print(f" second-order implications: {', '.join(risk.SecondOrderImplications)}")