Lesson 10 / 22
Preparation
Counting preparation in items: how twelve preparation items cut the six-step chain from alert to decision from 470 minutes to 182 minutes, pulling the containment moment from 656 to 368 and the items reached from 13 to 9, how the asset inventory's absence alone adds 49 minutes, how the communication tree earns 5.00 minutes per person-hour while forensic collection readiness stays at 0.11, and how pre-approved authority earns 103 minutes a year while cutting 233 legitimate work items.
Published Updated
In this lesson
- Models the chain from alert to decision as a step sequence and derives step minutes by preparation level
- Measures each preparation item with two numbers: the minutes its absence adds to the chain and its annual maintenance person-hours
- Counts together the minutes pre-approved containment authority earns and the legitimate work items it cuts
Contents
The previous topic built the detection pipeline: sources were collected, normalized, correlation rules were written, thresholds were tuned, and repeated response was automated. The question the topic left behind was this: what happens when an alert turns out to be right. The pipeline produced a correct alert; from here on, what gets counted is no longer the quality of the rule but the time between the moment the alert fires and the moment access stops.
Throughout this topic the unit of measure is twofold: minutes and items. Time to detect is the output of the detection pipeline and is given here as an input. What gets measured is time to contain — how many minutes pass between the alert and access stopping, and how many items are reached in those minutes. Preparation is this duration’s individually countable component: a plan, an authority matrix, or a communication tree is either ready on the day the incident starts or is written during the incident. The latter adds minutes.
Chain from Alert to Decision
The example is the fictional regional measurement network carried through the courses: branch collectors, a validator, billing, a subscriber portal, and work order services; a three-person shift. Both the incident and the records are fictional; there is no real organization, address, or event.
IR1: The alert fires 186 minutes after the incident starts and is correct; this value is the input coming from the detection pipeline. IR2: The access curve consists of fourteen items; each item becomes accessible at a specific minute and that item never closes again. The curve is data, not a measurement; no step sequence belonging to the attack side is written, only which item is accessed at which minute. IR3: The chain from alert to containment is six steps: verification, scope, authority, decision, selection, execution. Each step has an unprepared baseline number of minutes. IR4: There are twelve preparation items; a ready item shortens the minutes of the step it affects by a multiplier, a missing item does nothing — the step stays at its baseline. IR5: Each preparation item’s annual maintenance cost is in person-hours. IR6: Access stops the moment containment is applied; the number of items already reached by that point is the cost of a late decision.
// preparation/model.mjs — incident response preparation model: no real incident record. // The access curve, chain steps, and preparation items are data structures; durations are // fictional data. export const ALERT = 186; // minute the alert fires (output of the detection pipeline) // access curve: [minute, item name] — the item becomes accessible at that minute (data) export const ACCESS = [ [0, "run on collector-03"], [26, "collector-03 local identity store"], [58, "validator-01 service account"], [95, "collector-07"], [134, "collector-11"], [171, "validator-02"], [214, "billing read endpoint"], [263, "subscriber portal copy"], [318, "work order queue"], [372, "field laptop management channel"], [441, "backup store listing"], [505, "billing archive export"], [588, "second-region collector set"], [676, "management console read"]]; export const items = (dk) => ACCESS.filter(([t]) => t <= dk).length; // chain step: name, unprepared baseline minutes export const STEP = [["verification", 68], ["scope", 124], ["authority", 96], ["decision", 82], ["selection", 54], ["execution", 46]]; // preparation item: name, steps it affects, step multiplier, annual maintenance person-hours export const PREP = [ ["response plan", ["selection"], 0.55, 16], ["authority matrix", ["authority"], 0.45, 8], ["communication tree", ["decision"], 0.50, 6], ["asset inventory", ["scope"], 0.55, 24], ["log source map", ["verification"], 0.50, 12], ["backup access channel", ["execution"], 0.75, 10], ["pre-approved containment authority", ["authority"], 0.55, 4], ["identity response playbook", ["selection"], 0.65, 14], ["forensic collection readiness", ["execution"], 0.90, 18], ["external response support", ["decision"], 0.85, 5], ["tabletop exercise", STEP.map(([a]) => a), 0.88, 30], ["restore test", ["execution"], 0.85, 22]]; // chain step minutes and total for a given set of ready items export function chain(ready) { const dk = Object.fromEntries(STEP); for (const [name, steps, mult] of PREP) if (ready.includes(name)) for (const a of steps) dk[a] *= mult; const total = Math.round(Object.values(dk).reduce((s, v) => s + v, 0)); return { dk, total, containment: ALERT + total, items: items(ALERT + total) }; } export const FULL = PREP.map(([a]) => a); export const PARTIAL = ["response plan", "authority matrix", "communication tree", "asset inventory", "log source map", "backup access channel"]; // annual alert set: 6 of 24 verified alerts are real incidents (data) export const ALERTS_PER_YEAR = 24, REAL_PER_YEAR = 6, CUT_PER_HOUR = 26;
// preparation/measure.mjs — how many minutes the decision shortens when a preparation item // is ready, how many minutes and how many reached items a missing item adds, what pre-approved // authority's two-sided cost is. import { ALERT, STEP, PREP, FULL, PARTIAL, chain, items, ALERTS_PER_YEAR, REAL_PER_YEAR, CUT_PER_HOUR } from "./model.mjs"; const write = (g, ...s) => console.log(s.map((v, i) => (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join("")); const t0 = process.hrtime.bigint(); const D = { unprepared: chain([]), partial: chain(PARTIAL), full: chain(FULL) }; console.log(`alert fires at minute ${ALERT}; ${PREP.length} preparation items, ` + `${STEP.length} chain steps`); console.log("\n1. chain from alert to decision (minutes)"); const A = [-24, 14, 12, 10]; write(A, "step", "unprepared", "partial (6)", "full (12)"); for (const [a] of STEP) write(A, a, ...Object.values(D).map((r) => r.dk[a].toFixed(0))); write(A, "total", ...Object.values(D).map((r) => r.total)); write(A, "containment minutes", ...Object.values(D).map((r) => r.containment)); write(A, "items reached", ...Object.values(D).map((r) => `${r.items}/14`)); write(A, "annual person-hours", ...Object.entries({ unprepared: [], partial: PARTIAL, full: FULL }) .map(([, k]) => PREP.filter(([a]) => k.includes(a)) .reduce((s, h) => s + h[3], 0))); console.log("\n2. minutes added to the chain when an item is missing (removed one at a time from the full set)"); const B = [-38, 11, 10, 12, 14, 15]; write(B, "missing item", "total min", "+minutes", "containment", "annual p-hr", "min/p-hr"); const t = D.full; const ranked = PREP.map((h) => [h, chain(FULL.filter((a) => a !== h[0]))]) .sort((x, y) => y[1].total - x[1].total); for (const [h, r] of ranked) write(B, h[0], r.total, "+" + (r.total - t.total), r.containment, h[3], ((r.total - t.total) / h[3]).toFixed(2)); write(B, "(none missing)", t.total, "-", `${t.containment} (${t.items}/14)`, PREP.reduce((s, h) => s + h[3], 0), "-"); console.log("\n3. two sides of pre-approved containment authority (" + `${ALERTS_PER_YEAR} verified alerts a year, ${REAL_PER_YEAR} real incidents)`); const C = [-34, 14, 12, 13]; write(C, "run", "authority min", "annual gain", "annual cut"); for (const [a, k] of [["no pre-approval", FULL.filter((a) => a !== "pre-approved containment authority")], ["pre-approval", FULL], ["pre-approval, no log source map", FULL.filter((a) => a !== "log source map")]]) { const r = chain(k), approved = k.includes("pre-approved containment authority"); const gain = approved ? REAL_PER_YEAR * (chain(k.filter((a) => a !== "pre-approved containment authority")).dk.authority - r.dk.authority) : 0; const cut = approved ? (ALERTS_PER_YEAR - REAL_PER_YEAR) * (r.dk.verification / 60) * CUT_PER_HOUR : 0; write(C, a, r.dk.authority.toFixed(0), gain.toFixed(0) + " min", cut.toFixed(0) + " items"); } console.log("\n4. items reached as containment minute is scanned"); const E = [-16, 9, 9, 9, 9, 9, 9]; const scan = [200, 280, 362, 470, 560, 656]; write(E, "containment min", ...scan); write(E, "items reached", ...scan.map((d) => `${items(d)}/14`)); const ms = Number(process.hrtime.bigint() - t0) / 1e6; // raw measurement is not printed, only the band console.log(`\nthree levels and ${PREP.length} marginal runs within the 500 ms band: ` + (ms < 500 ? "yes" : "no"));
alert fires at minute 186; 12 preparation items, 6 chain steps 1. chain from alert to decision (minutes) step unprepared partial (6) full (12) verification 68 34 30 scope 124 68 60 authority 96 43 21 decision 82 41 31 selection 54 30 17 execution 46 35 23 total 470 251 182 containment minutes 656 437 368 items reached 13/14 10/14 9/14 annual person-hours 0 76 169 2. minutes added to the chain when an item is missing (removed one at a time from the full set) missing item total min +minutes containment annual p-hr min/p-hr asset inventory 231 +49 417 24 2.04 communication tree 212 +30 398 6 5.00 log source map 212 +30 398 12 2.50 authority matrix 207 +25 393 8 3.13 tabletop exercise 207 +25 393 30 0.83 pre-approved containment authority 199 +17 385 4 4.25 response plan 196 +14 382 16 0.88 identity response playbook 191 +9 377 14 0.64 backup access channel 189 +7 375 10 0.70 external response support 187 +5 373 5 1.00 restore test 186 +4 372 22 0.18 forensic collection readiness 184 +2 370 18 0.11 (none missing) 182 - 368 (9/14) 169 - 3. two sides of pre-approved containment authority (24 verified alerts a year, 6 real incidents) run authority min annual gain annual cut no pre-approval 38 0 min 0 items pre-approval 21 103 min 233 items pre-approval, no log source map 21 103 min 467 items 4. items reached as containment minute is scanned containment min 200 280 362 470 560 656 items reached 6/14 8/14 9/14 11/14 12/14 13/14 three levels and 12 marginal runs within the 500 ms band: yes
The numbers belong to the measurement class; their inputs are the assumptions above.
Three Preparation Levels
The first table converts preparation into minutes. With no item ready, the chain takes 470 minutes: the alert fires at minute 186, containment is applied at minute 656, and by then thirteen of the fourteen items have been reached. With six items it drops to 251 minutes, with twelve items to 182 minutes; containment is pulled to minute 368 and the items reached drop to nine.
The step breakdown shows where preparation touches. The two largest baselines are the scope (124 minutes) and authority (96 minutes) steps — that is, the questions “which assets were affected” and “who can cut access.” With full preparation, scope drops to 60 and authority to 21 minutes. The verification step drops from 68 to only 30 and remains the chain’s third-longest step even at full preparation; verification is not a paperwork task but a record-reading task, and it has a ceiling that preparation can only shorten so far.
The difference between the two levels is not evenly distributed. The first six items require 76 person-hours a year and cut 219 minutes from the chain — 2.88 minutes per person-hour. The second six items require 93 more person-hours and cut only 69 minutes; 0.74 minutes per person-hour. Preparation’s return is a diminishing curve: the first items touch the chain’s longest steps, the later ones split what is left.
The fourth table shows the same curve on its own. Pulling containment from minute 656 to 368 saves four items; pulling it from 368 to 280 saves one more. The curve is not flat: the item count rises fast in the early minutes, then thins out. This means preparation’s return is not constant either.
Minutes per Item
The second table counts preparation as items. When a single item is removed from the full set, the minutes added to the chain are that item’s real value. The asset inventory’s absence is the most expensive: it alone adds 49 minutes, because the scope step both has the longest baseline and, without an inventory, there is no starting list at all. The communication tree and the log source map each add thirty minutes; the authority matrix and the tabletop exercise each add twenty-five.
What these three items actually are gives the number its meaning. The asset inventory is the list that holds which machine runs which service and which network segment it sits on; if it is missing during an incident, the scope step first has to produce that list itself. The authority matrix writes down which role can carry out which action with which approval: cutting a network segment, locking a service account, or taking a field unit off the network are separate lines. The communication tree wires in advance which information goes to whom through which channel; if this tree is missing during an incident, the decision step is spent hunting for the right person.
The last column settles it: minutes per person-hour. The communication tree needs six person-hours of maintenance a year and earns 5.00 minutes per person-hour; pre-approved authority earns 4.25 with four person-hours; the authority matrix earns 3.13. The tabletop exercise is the most expensive item at thirty person-hours and stays at 0.83 — but it does not scale a single step, it scales all six at once, so its reach is broader than the table shows.
The two items at the bottom of the list deserve attention. The restore test yields 0.18 and forensic collection readiness 0.11 minutes per person-hour; together they spend forty person-hours and cut only six minutes from the chain. The only thing measured in this lesson is decision minutes. Forensic collection readiness’s payoff is not in this table — it is where whether evidence was collected gets counted; the restore test’s payoff shows up when how many stages recovery takes is measured. A preparation item measured on a single axis, if cut because it looks cheap on that axis, gets paid for on another axis.
Two Sides of Preparation
The third table shows that preparation is not free. Pre-approved containment authority lets the shift cut access without waiting for senior approval. IR7: 24 verified alerts are reviewed a year, six of which are real incidents; with pre-approval, the cut lasts until the alert is ruled out — that is, for the duration of the verification step — and cuts 26 legitimate work items an hour. Without pre-approval the authority step is 38 minutes, with pre-approval 21 minutes; across six real incidents it earns 103 minutes a year. The same authority cuts a total of 233 legitimate work items across the eighteen alerts that turn out not to be real.
The third row shows that two preparation items are linked to each other. When the log source map is missing, verification rises from 30 to 60 minutes; the minutes pre-approved authority earns stay the same (103), but the legitimate work it cuts rises to 467 items. The cost of early-cut authority depends on how quickly that cut can be reversed. Early-cut authority granted without fast verification produces a cost twice the minutes it earns. Preparation items are not independent rows; one item’s value changes depending on whether another item is ready, and minutes summed one at a time do not show this dependency.
Summary
- The chain from alert to containment is six steps; it takes 470 minutes unprepared, 251 with six items, and 182 with twelve items. The containment moment drops from 656 to 368, and items reached drop from 13 to 9.
- The two largest steps are scope (124-minute baseline) and authority (96 minutes); preparation brings these down to 60 and 21 minutes, while verification drops from 68 to only 30 and stays third in the chain.
- The cost of a single missing item is counted separately: asset inventory +49, communication tree and log source map +30, authority matrix and tabletop exercise +25 minutes.
- Gain per person-hour is 5.00 minutes for the communication tree and 4.25 for pre-approved authority; forensic collection readiness stays at 0.11 — its payoff is not on this axis, it is measured when evidence is counted.
- Pre-approved authority earns 103 minutes a year and cuts 233 legitimate work items; with the log source map missing, the same authority’s cut rises to 467 items.
Next Step
The chain’s first two steps were just single minute values in this lesson: verification 30, scope 60. Both have to answer a single question — is this alert really an incident, and how many assets were affected. The next lesson goes inside these two steps: which asset the alert points to, how many steps out from that asset you need to look, how many of the assets examined have logs, and how many affected assets a narrow scope leaves off the list.
To keep your progress and take notes, Log in
My notes
Log in to take notes.