Chapter 15 — Cross-service incident timeline integration
Lesson map
Lesson 15 published. Map, example, EX057.
flowchart TD
N0["Learning outcomes and connection"]
N1["15.1 A timeline has more than one axis"]
N2["15.2 Offline join-quality worksheet"]
N3["15.3 Build a defensible case narrative"]
N4["Subject synthesis"]
N0 --> N1 --> N2 --> N3 --> N4
N4 --> EX["Worked example"]
EX --> Q["Exercise EX057"]
Logical drawing
flowchart LR
N0["Learning outcomes and connection"]
N1["15.1 A timeline has more than one axis"]
N2["15.2 Offline join-quality worksheet"]
N3["15.3 Build a defensible case narrative"]
N4["Subject synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> Q["EX057"]
[Learning outcomes and connection]
|
v
[15.1 A timeline has more than one axis]
|
v
[15.2 Offline join-quality worksheet]
|
v
[15.3 Build a defensible case narrative]
|
v
[Subject synthesis]
|
v
[Worked example] --> [Exercise EX057]
Learning outcomes and connection
The learner will assemble a timeline across identity, host, application and support-desk records without promoting a matching label to a proven event chain. Chapter 14 yielded a deterministic set of claims and exceptions. Chapter 15 adds event time, source time, collection time, identifier namespace, join quality, missingness and alternative interpretations. An operator should be able to show a timeline to a service owner and state exactly which transitions remain unsupported. NIST SP 800-61 Rev. 3 informs response governance; the K15 packet is wholly synthetic.
15.1 A timeline has more than one axis
Use K12 accepted observations: I1 at 11:59:59 reports a success under s-7; I2 at 12:00:01 reports a denial under s-8; H1 at 12:00:02 reports host boot_b7; A1 at 12:00:03 reports r-601 queued under s-7. For this exercise add D15, a new fictional support-desk report received at 12:05:00: “A patron cannot find a booking.” D15 is a person reporting a symptom, not a transaction outcome. It gives no reservation ID, session ID or authoritative database read. This addition is a K15 branch release; do not retroactively claim D15 was present in K12 or the main LLR case. The K11 clock-offset worksheet concerned a separate K11 fixture; its offsets must not be silently pasted onto these K12 timestamps. Until custodians verify clocks, even strict chronological order across producers is provisional.
For every row record: raw object ID and immutable version; producer; event time with offset and uncertainty if supplied; ingestion and collection times if supplied; event type and literal principal/session/request fields; whether the row passed K12 validation; and which decision it might inform. “Unknown” is a valid, consequential field. The timeline should contain rejected A2 and duplicate A1 in an exception lane rather than pretending they never existed. A2's unparseable event time cannot be plotted as if corrected. A dashboard that omits that lane overstates completeness.
There are three join strengths. Literal co-occurrence: I1 and A1 both spell s-7; that is a candidate relation. Validated mapping: IdP and app owners confirm namespace, request propagation and source copies for the bounded interval; this can support a session relation. Authoritative outcome: a database receipt, with owner-verified semantics, establishes whether a write committed or rolled back. One level does not imply the next. The I2 denial under s-8 does not cancel a queued A1 under s-7. H1's boot says a host restarted; without component and dependency mapping, it cannot explain either record. D15 says a patron observed a missing booking; it may reflect a UI cache, failed write, wrong account or timing. A technical narrative should preserve these competing explanations.
15.2 Offline join-quality worksheet
This listing orders five literal classroom observations. It deliberately prints a candidate rather than an incident conclusion. It uses no network or filesystem. Python's datetime parser handles these explicitly UTC strings; it does not verify the producer clocks.
from datetime import datetime
events = [
("I1", "idp", "2026-10-11T11:59:59+00:00", "s-7", "success"),
("I2", "idp", "2026-10-11T12:00:01+00:00", "s-8", "denied"),
("H1", "host", "2026-10-11T12:00:02+00:00", "", "boot_b7"),
("A1", "app", "2026-10-11T12:00:03+00:00", "s-7", "r-601 queued"),
("D15", "desk", "2026-10-11T12:05:00+00:00", "", "booking missing report"),
]
ordered = sorted(events, key=lambda row: datetime.fromisoformat(row[2]))
print("order:", [row[0] for row in ordered])
matching = [(a[0], b[0]) for a in events for b in events
if a[1] == "idp" and b[1] == "app" and a[3] and a[3] == b[3]]
print("literal_session_candidates:", matching)
print("denied_app_match:", any(a[4] == "denied" and (a[0], b[0]) in matching
for a in events for b in events))
print("database_outcome:", "not supplied")
The order is I1, I2, H1, A1, D15 under supplied event-time strings. The +00:00 forms are normalized copies of K12's Z timestamps, not the original CSV bytes. The only literal session candidate is I1/A1. The denied-app match is False, and no DB outcome is supplied. Replacing I2's session with s-7 in a copy would change the candidate list and denied-app match, but it would not authenticate the shared namespace, give D15 an ID, or prove that a booking committed. The code's nested scan is adequate for five rows, not a scalable or fully validated correlation engine.
15.3 Build a defensible case narrative
Present a two-column narrative: observed in supplied packet and interpretation requiring a test. For example: “A1 says queued” belongs in the first column; “the application persisted r-601” belongs in the second, with a database-owner receipt request. “D15 reports missing booking” is observed; “A1 caused D15” requires a patron/reservation mapping and time-window check, under privacy approval. “I1 and A1 share s-7” is observed; “same authenticated session” requires a cross-producer map. The owner should provide the mapping definition, its valid period, and positive and negative examples; a one-off equal string is insufficient.
Confidence should attach to a claim and its evidence, not to the whole incident. A defensible note can say “high confidence that the supplied A1 string is queued under the K12 parser rules; low confidence that this packet establishes a DB outcome.” Confidence is lower if the raw export lacks authentication, the schema changed, clocks drifted or a known in-range control failed. Define the falsifier: a validated DB rollback receipt would disprove a “committed” claim; a validated different namespace would disprove the I1/A1 session join; an out-of-window support ticket would undermine a causal ordering. Do not use “no event” unless source coverage, interval, ingestion delay and query completeness have been tested.
A case handoff needs a version number. If a custodian later supplies a DB row, append a new timeline version with its raw receipt and an explicit note on what changed. Do not silently repair A2's bad time or overwrite a prior conclusion. NIST SP 800-86 is an older forensic reference for evidence-handling concepts; the exact K15 join rules are local teaching design and require system-owner validation in real work.
Exercises — subject 15
EX057 — Multi-lane chronology. Build a five-row accepted timeline plus a separate lane for A2 and duplicate A1. List producer, time status, literal claim, candidate join, owner and unknown for each accepted row. Evidence: two-lane worksheet. Rubric: 2 = all five rows and two exceptions with uncertainty, 1 = chronology without source limits, 0 = plots A2 at a fabricated time.
EX058 — Join lab and variant. Run §15.2, record four output lines, then change only I2's session to s-7 in a copy. Report changed lines and explain three claims the variant still cannot prove. Evidence: original/variant transcript. Rubric: 2 = exact tuples and bounded inference, 1 = correct Boolean only, 0 = calls a literal match a validated compromise.
EX059 — Competing hypotheses. Write at least three explanations for D15's report, each with a read-only discriminating source, custodian, scope and falsifier. Include at least one ordinary service-failure explanation and one potential unauthorized-change explanation without naming an attacker as fact. Evidence: hypothesis matrix. Rubric: 2 = distinct tests and privacy/authority gate, 1 = hypotheses without tests, 0 = treats D15 as DB proof.
EX060 — Versioned escalation. Compose a 150–220-word timeline note, then a two-sentence version 2 for a hypothetical new owner-validated DB rollback receipt on r-601. Preserve version 1, state whether D15 is now causally explained and identify a next service check. Evidence: versioned handoff. Rubric: 2 = proper update and still-unknown D15 link, 1 = receipt noted but causal leap, 0 = rewrites old evidence.
Subject synthesis
A sorted list is not a causal narrative. K15 gains value by recording the quality of each join, rejected rows and source clocks, then specifying the next owner-approved observation. Chapter 16 turns such a bounded narrative into a procedure another operator can execute or reject safely.
Continue studying — chapter 15 of 18
← Chapter 14 · Course chapter index · Chapter 16 →
Continue to the next authored lesson.