Back to Streaming Sketching

Streaming Matrix & Graph Lab

September 28, 2026 Wasil Zafar 21 min read

Unify matrix and dynamic-graph sketch experiments.

Table of Contents

  1. Frame the Matrix and Graph Questions
  2. Architect Shared Streaming Primitives
  3. Integrate Low-Rank and Connectivity Workflows
  4. Validate Accuracy, Scale and Recovery
  5. Demonstrate the Matrix and Graph Lab

Frame the Matrix and Graph Questions

Imagine watching a city through two narrow control-room displays. One display receives measurement rows—traffic, temperature, vibration—and must preserve the dominant directions without storing every row. The other receives road openings and closures and must answer whether two districts remain connected without retaining an expensive full history. Both problems compress a changing stream, but the questions and guarantees are different.

For a tiny matrix stream, rows (1,0), (0,1), (1,0) give the Gram matrix AᵀA=[[2,0],[0,1]]; the first coordinate is the dominant direction. For a graph stream, insert edges (A,B) and (B,C): A reaches C. Delete (B,C): A no longer reaches C. A low-rank summary must approximate quadratic energy ||Ax||²; a connectivity structure must preserve or recover enough crossing edges to certify components. Neither answer substitutes for the other.

A row stream appends vectors; a turnstile stream adds and removes weighted items, such as edges. A subspace approximation preserves the action of a matrix on important directions. Frequent Directions deterministically shrinks singular values to keep a compact row sketch; a randomized embedding applies a linear map with a probabilistic norm guarantee. Sparse recovery reconstructs a sparse vector from fewer linear measurements. An ℓ₀-sampler returns a uniformly distributed nonzero coordinate under its contract. A graph sparsifier preserves selected cut or spectral properties, while connectivity asks only whether paths exist.

Stakeholders include ML/platform engineers monitoring feature drift, graph-system teams tracking network reachability, SREs, capacity planners, security reviewers, and researchers comparing sketches. Acceptance requires explicit stream semantics, bounded state, deterministic seeded replay, version-compatible merges, exact small-instance oracles, mathematical error evidence, safe deletion handling, recoverable checkpoints, visible degradation, and no claim that a shared linear API creates a shared guarantee.

Two streaming views sharing one laboratoryMatrix rows and graph edge updates pass through shared versioned streaming primitives, then separate into low-rank and connectivity queries with distinct guarantees. Row updates(1,0), (0,1), (1,0) Edge updates+AB, +BC, −BC Shared stream substratevalidate • hash • accumulatesnapshot • merge • replayresource + version guards Geometry summarysubspace • energy • low rankspectral/Frobenius guarantee Graph summarysample • recover • connectcut/connectivity guarantee Shared plumbing, separate proof obligations and query contracts.
TermIntuitive meaningExact exampleNon-exampleAssumptionQuestion answered
Row streamVectors arriving one at a timeAppend (1,0) to matrix AEditing an old row silentlyDimension/version fixedWhat geometry does accumulated A contain?
Turnstile edge streamSigned edge multiplicity updates+AB,+BC,−BCDeletion below zero in strict turnstileEdge IDs/canonical order stableWhich edges are currently active?
Gram matrixPairwise feature energyAᵀA=[[2,0],[0,1]]Raw row logNumeric precision declaredHow much energy lies in direction x?
Subspace approximationCompact dominant geometryRank-1 span of first coordinateSampling arbitrary rowsError norm and target rank specifiedWhich low-dimensional space explains A?
Frequent DirectionsDeterministic shrinkage sketchℓ retained rows after SVD shrinkRandom projection without shrinkageAppend-only rowsHow can covariance loss be bounded?
Linear measurementAdditive compressed observationy=Φx; updates add ΔΦeᵢNon-versioned nonlinear cacheSame map/seed across statesWhat information can merge and recover?
ℓ₀-samplerSamples a nonzero coordinateReturn active edge from a cut vectorUniform vertex sampleTurnstile recovery succeeds with stated probabilityWhich crossing edge can reconnect components?
ConnectivityExistence of a pathA—B—C connects A to CShortest-path lengthActive graph semantics fixedAre u and v in the same component?
SparsifierSmaller graph preserving a propertyCut weights within 1±εAny spanning tree for spectral queriesSampling probabilities/weights validCan graph queries use fewer edges?
Warm-up

Frame the Matrix and Graph Questions

Process matrix rows (1,0), (0,1), (1,0). Add their outer products: after row 1, G=[[1,0],[0,0]]; after row 2, G=[[1,0],[0,1]]; after row 3, G=[[2,0],[0,1]]. Direction (1,0) has energy 2 and (0,1) has energy 1. Separately apply +AB,+BC,−BC: components change from {A,B},{C} to {A,B,C} and back to {A,B},{C}. Expected answers are dominant coordinate 1 and connected(A,C)=false at the end. Reflection: which state could be linearly merged across partitions, and what compatibility metadata would the merge need?

Architect Shared Streaming Primitives

The laboratory serves two workloads. Matrix producers append dense or sparse rows with up to 10,000 features; graph producers submit strict-turnstile edge updates over up to 100 million vertices. The envelope is {tenant, stream, update_id, event_time, kind, dimension_or_vertex_schema, payload, weight, algorithm_version}. A gateway authenticates, validates dimensions and weights, canonicalizes undirected edges, deduplicates update IDs, and writes an ordered replay log. Partition workers update exact shadow state for small streams and bounded sketches for production scale.

The shared measurement layer owns deterministic seed derivation, signed hashing, vector accumulation, numeric overflow checks, compatible merge, checkpoint epochs, and checksums. The matrix plane offers Frequent Directions for deterministic covariance-loss bounds and sparse/random embeddings for subspace tests. The graph plane maintains hierarchical sampled/recovery states over incidence/cut vectors and a spanning forest; replacement-edge recovery repairs deletions. Each result names stream model, algorithm, dimensions, seed ID, error/failure probability, epoch, watermark, and degradation status.

Targets include 250,000 updates/s per worker, update p99 under 5 ms, query p99 under 100 ms for bounded queries, checkpoints under 30 seconds, recovery under 10 minutes, and memory below 8 GiB per worker. Privacy limits isolate tenants and restrict raw rows/edges because feature directions and relationships can be sensitive. Threats include malformed sparse indices, NaN/overflow, adversarial cancellation, hash manipulation, deletion underflow, cardinality floods, replay duplication, corrupt checkpoints, cross-version merge, and unauthorized topology queries.

Streaming Matrix & Graph Lab: Architect Shared Streaming Primitives
flowchart TD
    P[Row and edge producers] --> G[Auth validate canonicalize]
    G --> L[Partitioned replay log]
    L --> M[Shared measurement runtime]
    M --> F[Frequent Directions]
    M --> E[Random embeddings]
    M --> Z[Graph recovery levels]
    F --> Q[Matrix query API]
    E --> Q
    Z --> C[Connectivity and sparsifier API]
    M --> S[Versioned checkpoints]
    Q --> R[Result plus guarantee]
    C --> R
    O[Operators] --> K[Config rollout control]
    K --> M
    M --> T[Metrics traces audit]
    classDef navy fill:#17365D,color:#fff,stroke:#102844;
    classDef teal fill:#147D84,color:#fff,stroke:#0c5c61;
    classDef crimson fill:#C6284D,color:#fff,stroke:#8e1935;
    classDef purple fill:#6C3BAA,color:#fff,stroke:#482675;
    class P,O navy;
    class G,L,M,K teal;
    class F,E,Z,S purple;
    class Q,C,R,T crimson;
Matrix and graph laboratory trust boundariesProducers enter an authenticated data plane with isolated partitions; checkpoint storage and query consumers are separate failure domains, while operators use a distinct control boundary. Authenticated tenant data plane Producersrows + edge deltas Gatewayschema • quota • dedup Partition Ameasurementsfailure domain 1 Partition Bmeasurementsfailure domain 2 Matrix + graph APIstenant-scoped guarantees Checkpoint storeseparate failure domain Query consumersmodels + graph services Operatorscontrol boundary Data partitions, checkpoints, consumers, and control plane remain independently authorized and recoverable.
CandidateGuaranteeScale / latencyMemoryOperational burdenPrivacyFailure recoveryDecision
Exact rows + SVDExact matrix answerExpensive recomputationO(nd)Simple oracle, poor scaleRetains raw rowsReplay full dataKeep for fixtures/small streams
Frequent DirectionsDeterministic covariance-loss boundPeriodic SVD of ℓ×d sketchO(ℓd)Numeric/SVD monitoringCompressed directions can leak featuresSnapshot rows; compatible merge/reduceSelect for append-only low-rank summaries
Sparse JL/subspace embeddingProbabilistic norm/subspace preservationFast sparse updateO(md) or implicit mapSeed and dimension calibrationLinear projections may leakRebuild/merge same mapSelect for regression/subspace experiments
Exact adjacency + BFSExact dynamic connectivityQuery O(V+E)O(V+E)Straightforward until largeFull topology retainedReplay edgesKeep as graph oracle
Recompute spanning forestExact after each batchHigh deletion costO(V+E)Batch schedulingFull topologyRebuild from active edgesFallback for bounded batches
Hierarchical ℓ₀ recoveryRandomized replacement-edge recoveryPolylog-style levels, complex constantsBounded sketch per vertex/levelStrong version/hash disciplineSketches still expose structureReplay/checkpoint compatible levelsSelect for research/prototype dynamic connectivity
Spectral sparsifierApproximate quadratic/cut structureSampling/reweighting overheadNear-linear sparse graphProbability and weights must be auditedReduced but meaningful topologyRebuild/versioned mergeSelect for Laplacian queries, not as connectivity proof alone
One generic sketch typeUniform API onlySuperficially simpleUnclearHides incompatible semanticsUnclearUnsafe coercionReject

The central invariant is linear, version-compatible state evolution: the same logical update produces the same signed measurement, and only states with identical semantics, dimensions, seeds, numeric format, and epoch rules may merge. Launch is blocked by deletion underflow, silent overflow, cross-version merge, unlabelled probability, unbounded state, or a query using the wrong guarantee.

Integrate Low-Rank and Connectivity Workflows

Build vertical slices. Slice 1 validates row/edge envelopes and maintains exact Gram, adjacency, and replay oracles. Slice 2 introduces the shared deterministic hashing and additive measurement interface. Slice 3 adds Frequent Directions with covariance tests. Slice 4 adds graph sampling/recovery levels and spanning-forest repair. Slice 5 adds partition merges, snapshots, migrations, shadow comparisons, and degraded fallbacks. Each slice can ingest, query, checkpoint, restore, and prove its resource ceiling independently.

Stable interfaces are apply(update), query(request), merge(other), snapshot(), and restore(bytes), with capability metadata separating append-only matrices from strict-turnstile graphs. Configuration validates feature dimension, sketch rows, vertex range, recovery levels, numeric type, seed identity, and cell/edge budgets before allocation. Snapshots contain algorithm/version, stream model, dimensions, seeds, epoch, watermark, checksum, and payload. Unsupported versions trigger replay or STATE_INCOMPATIBLE; safe fallback may serve a labelled exact small-state result, batch rebuild, stale checkpoint, or explicit rejection.

from dataclasses import dataclass
from collections import defaultdict, deque
from typing import Iterable

@dataclass(frozen=True)
class Config:
    dimension: int = 2
    max_vertices: int = 1000
    max_edges: int = 10_000
    format_version: int = 1
    def validate(self) -> None:
        if not 1 <= self.dimension <= 10_000: raise ValueError("unsafe matrix dimension")
        if not 1 <= self.max_vertices <= 1_000_000: raise ValueError("unsafe vertex limit")
        if not 1 <= self.max_edges <= 10_000_000: raise ValueError("unsafe edge limit")
        if self.format_version != 1: raise ValueError("unsupported format version")

class MatrixGraphLab:
    def __init__(self, config: Config):
        config.validate(); self.config = config
        self.gram = [[0.0]*config.dimension for _ in range(config.dimension)]
        self.rows = 0
        self.edges: dict[tuple[str,str], int] = {}

    def add_row(self, row: Iterable[float]) -> None:
        values = tuple(float(x) for x in row)
        if len(values) != self.config.dimension: raise ValueError("row dimension mismatch")
        if any(x != x or abs(x) > 1e100 for x in values): raise ValueError("non-finite/unsafe value")
        for i, x in enumerate(values):
            for j, y in enumerate(values): self.gram[i][j] += x*y
        self.rows += 1

    def update_edge(self, u: str, v: str, delta: int) -> None:
        if not u or not v or u == v or delta not in (-1,1): raise ValueError("invalid edge update")
        edge = tuple(sorted((u,v)))
        current = self.edges.get(edge, 0)
        if current + delta not in (0,1): raise ValueError("strict-turnstile edge violation")
        if delta == 1 and current == 0 and len(self.edges) >= self.config.max_edges:
            raise MemoryError("edge budget exceeded")
        if current + delta == 0: self.edges.pop(edge, None)
        else: self.edges[edge] = 1

    def energy(self, direction: Iterable[float]) -> float:
        x = tuple(float(v) for v in direction)
        if len(x) != self.config.dimension: raise ValueError("direction mismatch")
        return sum(x[i]*self.gram[i][j]*x[j]
                   for i in range(self.config.dimension) for j in range(self.config.dimension))

    def connected(self, source: str, target: str) -> bool:
        if source == target: return True
        graph = defaultdict(list)
        for (u,v) in self.edges: graph[u].append(v); graph[v].append(u)
        queue, seen = deque([source]), {source}
        while queue:
            node = queue.popleft()
            for nxt in graph[node]:
                if nxt == target: return True
                if nxt not in seen: seen.add(nxt); queue.append(nxt)
        return False

    def merge(self, other: "MatrixGraphLab") -> "MatrixGraphLab":
        if self.config != other.config: raise ValueError("incompatible state")
        overlap = set(self.edges) & set(other.edges)
        if overlap: raise ValueError("edge partitions overlap")
        out = MatrixGraphLab(self.config); out.rows = self.rows + other.rows
        out.gram = [[self.gram[i][j] + other.gram[i][j] for j in range(self.config.dimension)]
                    for i in range(self.config.dimension)]
        out.edges = self.edges | other.edges
        if len(out.edges) > self.config.max_edges: raise MemoryError("merged edge budget exceeded")
        return out

def self_test() -> None:
    cfg = Config(dimension=2, max_vertices=10, max_edges=10)
    lab = MatrixGraphLab(cfg)
    for row in [(1,0),(0,1),(1,0)]: lab.add_row(row)
    assert lab.gram == [[2.0,0.0],[0.0,1.0]]
    assert lab.energy((1,0)) == 2 and lab.energy((0,1)) == 1
    lab.update_edge("A","B",1); lab.update_edge("B","C",1)
    assert lab.connected("A","C")
    lab.update_edge("B","C",-1); assert not lab.connected("A","C")
    left, right = MatrixGraphLab(cfg), MatrixGraphLab(cfg)
    left.add_row((1,0)); left.update_edge("A","B",1)
    right.add_row((0,1)); right.update_edge("C","D",1)
    merged = left.merge(right)
    assert merged.gram == [[1.0,0.0],[0.0,1.0]] and len(merged.edges) == 2
    try: lab.update_edge("B","C",-1)
    except ValueError: pass
    else: raise AssertionError("deletion underflow accepted")
    try: left.merge(MatrixGraphLab(Config(dimension=3)))
    except ValueError: pass
    else: raise AssertionError("incompatible merge accepted")
    print("integration checks passed", lab.gram, lab.connected("A","C"))

if __name__ == "__main__": self_test()
Streaming Matrix & Graph Lab: Integrate Low-Rank and Connectivity Workflows
flowchart TD
    C[Typed update contracts] --> X[Exact Gram and graph oracles]
    X --> M[Shared linear measurements]
    M --> F[Frequent Directions slice]
    M --> L[Graph recovery levels]
    F --> U[Unified versioned state]
    L --> U
    U --> S[Snapshot merge replay]
    S --> K[Shadow canary]
    K -->|Oracle and SLO pass| P[Progressive promotion]
    K -->|Error or invariant fail| R[Rollback exact baseline]
    R --> X
    classDef navy fill:#17365D,color:#fff,stroke:#102844;
    classDef teal fill:#147D84,color:#fff,stroke:#0c5c61;
    classDef crimson fill:#C6284D,color:#fff,stroke:#8e1935;
    classDef purple fill:#6C3BAA,color:#fff,stroke:#482675;
    class C,X navy;
    class M,F,L,U teal;
    class S,K purple;
    class P,R crimson;
Build

Integrate Low-Rank and Connectivity Workflows: Streaming Matrix & Graph Lab

Create contracts.py, matrix_oracle.py, graph_oracle.py, measurements.py, checkpoints.py, and test_replay.py. Replay rows (1,0),(0,1),(1,0); checkpoint 1 requires Gram [[2,0],[0,1]] and directional energies 2 and 1. Apply +AB,+BC; checkpoint 2 requires A connected to C, then −BC makes it disconnected. Partition rows and disjoint edges, merge, and compare byte-stable numeric state with a single logical replay. Add Frequent Directions and graph recovery adapters behind the same envelope, but run separate oracle assertions for covariance energy and connectivity. Reject dimension mismatch, seed/version mismatch, duplicate edge insertion, deletion underflow, NaN, and budget overflow before mutation. Done means normal queries, deterministic replay, compatible merge, recovery, bounded state, and every failure path pass in one command.

Validate Accuracy, Scale and Recovery

Verification begins with exact algebra and graph traversal. Unit tests cover outer products, deterministic hashing, signed updates, shrinkage, sampling levels, forest operations, serialization, and compatibility. Property tests assert Gram symmetry and positive semidefinite quadratic forms, Frequent Directions covariance-loss bounds on small matrices, embedding norm preservation across preregistered seeds, strict-turnstile nonnegativity, forest acyclicity, and equality between connectivity answers and BFS on active-edge oracles.

An approachable end-to-end case is the two-dimensional matrix and three-vertex graph above. The professional workload combines 10,000-feature sparse rows with rank/drift changes and a 100-million-vertex graph with bursty inserts, adversarial deletions, bridge-edge churn, dense communities, and partition merges. Targets include 250,000 updates/s/worker, update p99 <5 ms, bounded query p99 <100 ms, matrix error within configured theorem/empirical envelope, zero connectivity mismatch on oracle-sized shadows, memory <8 GiB, checkpoint <30 s, and recovery <10 min.

Fault injection kills a worker during checkpoint, drops a partition, corrupts a measurement cell, rotates a seed without a version bump, introduces NaN/overflow, reorders deletions, exhausts one recovery level, and delays storage. Metrics expose lag, rejected/duplicate updates, numeric magnitude, shrink events, residual/covariance error, sampler failures, recovery attempts, forest repairs, shadow BFS mismatch, state bytes, checkpoint age, and incompatible merges. Traces connect update, measurement, query, recovery, and checkpoint; audit logs preserve configuration, sensitive queries, changes, incidents, and decisions.

Verification and observability surfaceAlgebraic and graph tests, shadow oracles, scale tests, and fault injection feed metrics, traces, alerts, and audit evidence for promote, hold, or rollback. Algebra + graph testsenergy • forest • turnstile Shadow exact oraclesGram/SVD • BFS • cuts Load + fault testsdrift • churn • recovery Metrics + tracesnumeric and graph signals Audit evidenceversion • query • incident Alertserror • mismatch • quota Evidence dossierbounds + replay + timeline Operatorpromote • holdrollback Matrix and graph evidence remain distinct until an owned operational decision.
Requirement / guaranteeTest oracleWorkloadMetric and thresholdFailure injectionEvidenceOwner
Row semantics are exactDirect outer-product sumDense/sparse fixturesGram equality on exact baselineDimension mismatch, NaNAlgebra test logMatrix owner
FD bound holdsExact SVD/covarianceLow-rank, flat, drifting spectraObserved covariance loss within configured boundRepeated near-equal singular valuesBound plots and matricesAlgorithms reviewer
Embedding is calibratedExact vector normsFixed subspace across 30+ seedsFailure frequency within declared δ toleranceSeed reuse/correlationDistortion distribution and seed manifestStatistics reviewer
Turnstile state stays validExact edge multiplicity mapInsert/delete/churnZero negative multiplicities or silent underflowDuplicate deletionRejection auditGraph owner
Connectivity is correctBFS/union-rebuild oracleCommunities, bridges, churnZero mismatch on shadow-sized graphsDelete bridge and exhaust levelQuery diff and recovery traceGraph correctness lead
Merge matches contractSingle-stream replay1, 8, 64 disjoint partitionsState/query difference within algorithm guaranteeSeed/version mismatch, overlapMerge matrixPlatform lead
Performance meets SLOLoad clock + allocator250k updates/s/workerupdate p99 <5 ms; query p99 <100 ms; memory <8 GiBHot partition and high dimensionDashboard and heap profileSRE
Recovery is safeChecksum + replay hashWorker loss during checkpointRTO <10 min; corrupt cell quarantinedKill worker, flip byteRecovery timelineIncident commander
Results are interpretableResult-schema validatorAll API queries100% include semantics/error/epoch/degradationDrop metadata fieldContract reportAPI owner
Tenant/privacy isolationAuthorization oracleCross-tenant row/edge probesZero unauthorized state/query accessForged tenant tokenSecurity test and access auditSecurity owner
Production

Validate Accuracy, Scale and Recovery: Streaming Matrix & Graph Lab

Run a 40-minute trial with sparse 10,000-dimensional rows containing rank shifts and graph updates over 100 million vertex IDs with bridge churn. Ramp to 250,000 combined updates/s/worker; require update p99 <5 ms, bounded-query p99 <100 ms, memory <8 GiB, matrix errors inside the configured envelope, and zero BFS mismatch on sampled shadow components. At minute 10 inject NaN and deletion underflow; expect rejection before mutation. At minute 18 remove a bridge and exhaust one recovery level; expect escalation or labelled degradation, never a fabricated answer. At minute 25 kill a worker during checkpoint; expect recovery <10 minutes. At minute 32 corrupt a cell and rotate a seed; expect checksum and compatibility quarantine. Roll back on any silent numeric corruption, connectivity mismatch, cross-version merge, isolation breach, or sustained SLO failure. Record GO, CONDITIONAL GO, or NO-GO with error plots, replay hashes, traces, cost, owners, and expiry dates.

Demonstrate the Matrix and Graph Lab

The release bundle contains update/query schemas, stream-model definitions, matrix and graph adapter contracts, parameter calculators, pinned dependencies, seeded datasets, benchmark commands and raw results, mathematical/correctness dossier, migration matrix, privacy review, dashboards, alerts, and an operational runbook. Every artifact names its version, owner, generation command, review date, and the theorem or empirical claim it supports.

The runbook begins with numeric growth, covariance drift, sampler/recovery failure, forest mismatch, deletion underflow, lag, quota breach, stale checkpoint, and incompatible state. It gives diagnostics, thresholds, safe fallbacks, escalation, rollback, and evidence preservation. The demonstration computes the tiny Gram matrix and connectivity trace, shows separate guarantee envelopes, partitions and merges compatible state, rejects dimension/seed mismatch, restores a checkpoint, corrupts one cell, and ends with the professional workload dashboard.

Peer reviewers ask: Are append-only and turnstile semantics explicit? Which operations are genuinely linear and mergeable? Does every query cite the right norm or failure probability? Can adversarial cancellation or overflow invalidate state? What happens when recovery fails? Can a matrix projection or graph sketch reveal sensitive relationships? Handoff requires tagged source, checksums, one-command tests, benchmark provenance, signed dossier, rehearsed recovery/rollback, on-call ownership, and no undocumented approximation.

Deliverable

Demonstrate the Matrix and Graph Lab: Streaming Matrix & Graph Lab

Final checklist: (1) build from a clean checkout; (2) run algebra, property, replay, merge, load, security, and fault suites; (3) publish schemas, semantics, parameters, and result envelopes; (4) attach proofs/references and empirical calibration; (5) archive datasets, seeds, environment lock, commands, and raw benchmarks; (6) sign correctness, statistics, operations, and privacy reviews; (7) rehearse deletion recovery, corrupt-checkpoint quarantine, and rollback; (8) assign dashboard, alert, and on-call owners. Demo the 2D Gram/energy trace, A–B–C connectivity change, compatible partition merge, incompatible-version rejection, snapshot recovery, and shadow-oracle dashboard. Score 0–2 for matrix correctness, graph correctness, contract clarity, reproducibility, bounded resources, observability/recovery, privacy, and documentation; require ≥14/16 with no zero. Stretch goals: spectral sparsification, regression from embeddings, distributed forest recovery, and GPU-accelerated FD. Milestones: production FD adapter, calibrated graph recovery, then shared distributed measurement service.

Launch only with separate matrix and graph guarantees, exact shadow evidence, version-safe linear updates, bounded resources, privacy controls, and rehearsed recovery. Known risks include numeric instability, weak hash assumptions, adversarial deletions, recovery failure, and structural leakage; ask which query becomes unsafe when an assumption breaks, then make calibrated replacement-edge recovery with explicit failure evidence the next milestone.