Connect incident claims with contrast, order and cautiously reviewed cause, then generate a handoff that preserves uncertainty.
Project: build a reviewable incident discourse map
Define the handoff contract
An incident handoff must tell the next responder what happened, what was claimed and what remains uncertain. Ingest versioned updates with authors and timestamps. Segment them into claim units, then attach relation proposals with evidence spans. Keep quoted hypotheses attributed. The map can inform a draft summary, but only reviewed causal edges may become causal prose. Unit and relation scope fixes the graph shape.
Construct a difficult case set
Include a deployment followed by an alarm, a cache flush followed by recovery, a correction that retracts an earlier explanation and two parallel incidents with similar terms. Mark explicit connectives, implicit relation candidates, speaker attribution and negation. Group all updates from one incident in the same evaluation split. Reviewers should label when the evidence supports only order, even if the causal story sounds convincing. Implicit relation policy prevents automatic promotion.
Build the staged map
Each node stores source revision, span and speaker; each edge stores relation label, direction, evidence and review state. Reject cross-incident edges unless a human explicitly links the incidents. When a note is revised, mark derived edges stale and ask for revalidation. Surface conflicting edges side by side instead of selecting the higher model score. A handoff generator should receive only active, access-permitted nodes and the accepted relations relevant to its audience.
Verify the released handoff
Compare the draft with the source map line by line for omitted critical events, unsupported cause, missing attribution and stale revisions. Report these errors and reviewer minutes, alongside relation-label precision. Shadow the workflow on resolved incidents before using it during a live response. If evidence is insufficient, the handoff should state the observed order and unresolved cause. Preserve the original updates for audit and incident-scoped rollback.
Implementation
def handoff_edges(edges, allowed_incident, active_revision):
accepted = []
for edge in edges:
if edge["incident_id"] != allowed_incident:
continue
if edge["source_revision"] != active_revision:
continue
if edge["relation"] == "cause" and edge["review_state"] != "accepted":
continue
accepted.append(edge)
return accepted
edges = [{"incident_id": "inc-47", "source_revision": "r3",
"relation": "temporal", "review_state": "proposed"},
{"incident_id": "inc-47", "source_revision": "r3",
"relation": "cause", "review_state": "review"}]
assert [edge["relation"] for edge in handoff_edges(edges, "inc-47", "r3")] == ["temporal"]
Performance and operating cost
Filtering e edges is O(e) time and O(e) output space. Candidate extraction and human review dominate the full workflow; a dense all-pairs candidate stage grows quadratically in claim units. Keep section and incident boundaries early. Measure unsupported causal statements in the final handoff, since a correct graph that is rendered as stronger prose still fails the user.
Common Mistakes
- Publishing a causal edge that has only adjacency evidence.
- Combining claims from different incidents because service names match.
- Keeping an edge active after its source note is revised.
- Evaluating graph labels while ignoring the generated handoff wording.
