The map that moved the bridge
Three flood-response teams divide a river corridor into overlapping zones. North Team maps the upstream road network in its own grid. East Team maps the bridge approaches in another. South Team maps the evacuation route in a third. Each team checks its hand-off with the next. Shared landmarks line up. The radio operator therefore reports that the three maps are consistent.
Then the command centre stitches the maps into one operational view. The bridge has moved thirty metres.
The first reaction is practical: average the coordinates. That feels reasonable because each local survey is accurate within its own zone. Yet averaging assumes that all three teams are already speaking the same coordinate language. They are not. North-to-East adds a ten-metre origin shift. East-to-South adds another ten. South-to-North, according to its own conversion sheet, subtracts only ten. Travel around the loop and the same landmark returns ten metres away from itself.
No team supplied an obviously absurd number. No single hand-off looked illegal in isolation. The failure lived in the composition of hand-offs. The maps did more than disagree about a value. Their translation rules failed to close.
This is the local-to-global problem in its most useful form. Local descriptions can be individually valid and pairwise interpretable while the whole still lacks a coherent state. The remedy is not a more confident average. It is a structure that records what each region can say, how its claims restrict to an overlap, and whether all translation paths agree. That structure is a sheaf.
The seam is where meaning changes
Imagine two weather stations ten kilometres apart. One reports 20. The other reports 68. A naive consistency check sees a gap of forty-eight units. A typed check asks a prior question: what does each number mean? The first is Celsius. The second is Fahrenheit. Once both are translated onto the overlap variable, air temperature in Celsius, the discrepancy vanishes.
The important object is not either number. It is the map that carries each local description into a shared comparison space. A sheaf makes that map explicit.
From patches to a sheaf
Start with a space divided into regions. A region may be geographic, temporal, organisational or conceptual. To each region U, assign the descriptions that are valid there. A description might be a continuous function, a database record, a coordinate frame, a probability distribution or a set of permitted system states.
If V sits inside U, there is a restriction map from descriptions on U to descriptions on V. Restriction answers a concrete question: what does this larger claim say when viewed only on the smaller overlap?
A presheaf records regions, local descriptions and restrictions. A sheaf adds two conditions. Compatible pieces must glue into a global description, and that global description must be unique. The formal definition says that when local sections agree after restriction to every overlap, there exists exactly one section over their union that restricts back to them. This is the standard sheaf condition.[1]
Local sections
sA is valid on region A. sB is valid on region B. Their native formats may differ.
Restriction to A ∩ B
Each section is translated into the shared overlap. Compatibility means the two restricted values are equal.
Unique global section
A single section s exists on A ∪ B and recovers both local sections when restricted back.
Gluing succeeds because every local description is compared only after both sides have been carried into the same overlap space. Raw equality is neither required nor usually meaningful. What must agree are the restricted descriptions.
Station A says 20 °C. Station B says 68 °F. The overlap variable is Celsius. A restricts by the identity map. B restricts by (F − 32) × 5/9. Both produce 20. The sections glue. If the translator omits −32, B restricts to 37.8. The local readings did not change, but the assignment no longer forms a compatible family.
This corrects a common slogan. It is misleading to say that “even compatible local sections of a sheaf might not glue”. For an actual sheaf, compatibility over a cover is exactly what guarantees unique gluing. Failure appears because the supplied local assignment is incompatible, because the proposed restriction architecture is only a presheaf, because an extension problem has a non-zero obstruction, or because the model forgot information needed for uniqueness.
The gluing axiom is established mathematics. Cellular sheaves make the idea finite and computable by attaching vector spaces and maps to cells in a complex.[2] The use of sheaves for sensor integration, network analysis and data fusion is a published applied programme, not a proof that every integration problem should use sheaf theory.[3]
flowchart LR A["The map that moved the bridge"] --> B["The seam is where meaning changes"] B --> C["The loop that local checks<br/>cannot see"] C --> D["Noise, ambiguity and false<br/>agreement"] D -. "re-test" .-> A classDef first fill:#0a1424,stroke:#007D68,stroke-width:2px,color:#e6f3ff classDef step fill:#0a1424,stroke:#3f7da0,stroke-width:1px,color:#e6f3ff class A first class B,C,D step
The loop that local checks cannot see
A chain of translations is forgiving. Choose a value at the first node, apply each local rule, and every later node receives a value. Nothing forces the final result to revisit its starting point. A loop is different. It creates a counterfactual route back to the same place. The composed translation must return the original value.
The smallest obstruction you can calculate mentally
Let each node hold one real number. The edge from A to B says that B is two units above A. The edge from B to C says that C is three units above B. The final edge says that A is four units below C.
xC − xB = 3
xA − xC = −4
Add the left sides. Every variable cancels, so the result must be zero. Add the right sides and the result is one. No assignment can satisfy all three equations. The contradiction is not located at one node. It is carried by the cycle.
Anchor A at zero and fit B and C by least squares. The best values are approximately xB = 1.667 and xC = 4.333. Each edge misses its target by one third. The fitted state is useful as a repair proposal, but it is not an exact gluing. The residual did not disappear. It was distributed.
What cohomology adds
Write all node values as a vector x. Let the operator δ compute the difference demanded on every edge. In the homogeneous case, a global section satisfies δx = 0. In the affine case above, the target edge offsets form a vector b, and a global assignment must satisfy:
The equation has a solution exactly when b lies in the image of δ. On a graph, adding a node potential changes edge offsets by a coboundary. What remains after every such local correction is the cohomology class of the cycle defect. For the triangle, the class is witnessed by the sum around the loop.
Cohomology is therefore not a mystical global summary. It records a defect that no redistribution of local coordinates can remove. In higher-dimensional settings the algebra is richer, but the causal intuition survives: some conflicts live on overlaps, while others appear only when overlap relations are composed around a closed structure.
A non-zero cohomological witness can certify an obstruction in the model being analysed. A zero witness need not prove that every desired global object exists. In the sheaf-theoretic treatment of contextuality, for example, a non-vanishing Čech cohomology class is sufficient but not necessary for contextuality.[7] The diagnostic has a declared scope.
Cycles are not the enemy
It would be easy to conclude that cycles create inconsistency. They do not. A consistent cycle closes exactly and supplies valuable redundancy. A tree can always propagate relative values, even when one translator is wrong. With no alternative path, the error is invisible. The cycle adds a testable equality between two routes.
Database theory shows a related structural divide. For relational and bag-valued schemas, acyclic hypergraphs enjoy a local-to-global property: pairwise consistency can guarantee global consistency. Cyclic schemas require more care, and for bag consistency the decision problem becomes NP-complete for fixed cyclic schemas in the cited result.[9] This does not mean every cycle is computationally hard. It means topology changes what local checks can establish.
Abramsky and Brandenburger model quantum contextuality as an obstruction to a global section over a measurement cover.[6] Distributed-systems research has likewise used contextuality to characterise failures of global consistency among relative execution traces.[12] The shared structure is local descriptions plus overlap constraints. The physical interpretation does not transfer automatically.
Noise, ambiguity and false agreement
Exact equality is a poor operating assumption for sensors, human reports and learned models. Measurements drift. Timestamps round. Language mappings lose detail. A useful local-to-global method must say more than “glues” or “does not glue”. It must quantify mismatch without erasing its structure.
The residual lives on the overlap
For a cellular sheaf on a graph, each node may hold a vector in its own local space. Each edge has a shared comparison space. The restriction map from an endpoint to an edge translates that endpoint’s state into the shared space. For an edge e joining u and v, define the mismatch:
xuthe local state proposed at nodeuRu→ethe typed translation from nodeuinto edgee’s overlap spacerethe disagreement after both endpoints have been translated into the same space
Stack all residuals into δx. A weighted inconsistency energy is:
Every weight we is an assumption about confidence or consequence. The equation is useful only when the local spaces, translations, norms and weights are justified. Under those assumptions, minimising E finds the state that least violates the overlap constraints. The associated sheaf Laplacian is L = δ*Wδ. Its kernel is the space of exact global sections in the linear setting, while its spectrum describes aspects of how disagreement propagates.[5]
d across three edges, giving minimum squared energy d²/3. The curve measures repair cost, not truth. Accessible description: a symmetric parabola touches zero at zero drift and rises as positive or negative cycle drift grows.Robinson’s consistency radius provides a related approach for sheaves of pseudometric spaces. It measures disagreement among restricted local assignments, supports consistency filtrations and is stable under specified perturbations.[4] The practical lesson is broader than any one norm: noise should soften equality, not erase the topology of where disagreement occurs.
Four questions that a single score confuses
Suppose an optimiser returns a very small energy. Can the system act? Not yet. Four different questions remain.
Residual asks how far the supplied assignment lies from satisfying the overlap rules. Obstruction asks whether any exact global assignment can satisfy the stated local constraints. Ambiguity asks how many materially different global states remain possible. Stability asks how much the conclusion moves when data or restriction maps are perturbed.
These quantities can vary independently. A tree of precise relative offsets can have zero residual and no cycle obstruction, yet still float by an unknown global origin. A heavily redundant network can determine a unique state but remain fragile if many constraints are almost dependent. A noisy loop can have a small residual but a repeatable non-zero closure error that identifies a biased translator.
World state
Work order, asset condition, task completion and current operational twin.
Installed part
Serial number, batch, compatibility, installation event and inspection result.
Authority
Identity, role, permitted action, expiry, separation of duties and revocation state.
Evidence and outcome
Decision receipt, effect receipt, readback, verified outcome and recovery point.
A planning agent proposes reopening a machine after a bearing replacement. The work-order service says the task is complete. The inventory service says bearing B-204 is installed. The authority service records an engineer’s approval for bearing B-203. The effect ledger confirms a successful test run after B-204 was installed.
Every local record is valid in its own system. A dashboard that checks only “task complete”, “approval present” and “test passed” returns green. A sheaf-like overlap contract carries the bearing serial into the authority comparison space. The approval and installed-part sections fail to agree. The correct outcome is not “mostly consistent”. The proposed release lacks a global authorised state.
This boundary experiment matters for human-machine systems. Intent, identity, world state, permitted context, model proposal, authority, typed action, evidence, verified outcome and recovery are not interchangeable fields. Collapsing them into “memory” makes incompatible histories look identical. A global state is only as discriminating as the overlaps it preserves.
Two laboratories report a pressure profile. Their overlap map retains only the label “safe” or “unsafe”. Both restrict to “safe”, so gluing succeeds. Yet one profile is 2% below the safety limit and the other is 40% below. For a binary dispatch decision, the overlap may be sufficient. For forecasting margin erosion, it destroys decision-relevant information. The issue is not obstruction. It is ambiguity created by a lossy restriction.
| Diagnostic | Question | Typical witness | Correct response | What zero does not prove |
|---|---|---|---|---|
| Residual | How far is this assignment from the overlap rules? | Non-zero edge mismatch or consistency radius | Recalibrate, reweight or inspect noisy sources | That an exact global state exists for every required field |
| Obstruction | Can any exact assignment satisfy the constraints? | Cycle closure error or non-zero obstruction class | Repair a translator, constraint or local claim | That the model’s ontology is true or complete |
| Ambiguity | How many decision-distinct global states remain? | Nullity, unanchored component or lossy overlap | Add an anchor, richer overlap or new measurement | That the selected state is factually correct |
| Stability | Would a small perturbation change the conclusion? | Small spectral margin or high condition sensitivity | Collect independent evidence or reduce consequence | That the stable consensus is not a shared falsehood |
Constraint solvers, factor graphs, database joins and type systems can solve many local-to-global problems with less machinery. Use them when all variables already inhabit one schema and translations are trivial. Sheaf language earns its cost when local domains differ, overlaps carry explicit maps, coverage changes, or topology itself controls what local checks establish. A decorative sheaf is worse than a clear constraint graph.
A system that localises inconsistency to overlap maps and cycle witnesses will recover faster than one that reports only a global contradiction score. This would be strengthened by lower repair time and fewer unnecessary data rejections in matched failure-injection trials. It would be weakened if ordinary constraint provenance identifies the same repair with equal effort. The smallest useful test is a synthetic network with one biased translator, one noisy source and one lossy overlap.
stateDiagram-v2 [*] --> Claim state "From patches to a sheaf" as Claim state "The smallest obstruction you<br/>can calculate mentally" as Test state "What cohomology adds" as Revision Claim --> Test: expose mechanism Test --> Decision: evidence survives Test --> Revision: rival survives Revision --> Claim: narrow or rebuild Decision --> [*]
The gluing gate
The theory becomes operational when it changes a release decision. The proposed instrument here is a Gluing Assurance Record, or GAR. It is not a new theorem. It is a practitioner synthesis that packages established sheaf and linear-algebraic ideas into one reviewable decision object.
A GAR should be versioned with the candidate boundary, local spaces, restriction maps, observations, weights and decision threshold. Its four core diagnostics are:
- Compatibility residual: the weighted mismatch of the supplied assignment on each overlap.
- Cycle obstruction: a path or cohomological witness showing that no exact global assignment satisfies the stated constraints.
- Ambiguity dimension: the remaining degrees of freedom after all constraints and anchors are applied.
- Stability margin: the resistance of the conclusion to small perturbations in data or translations.
The record also states the permitted decision. A GAR for “may display a consolidated dashboard” does not authorise “may execute an irreversible action”. The global section is scoped to the variables and relations encoded in the model.
Repairable disagreement and structural impossibility are not the same failure. A residual may shrink when observations are denoised. A cycle obstruction persists until a claim or translation rule changes. Ambiguity requires more information, while fragility requires more independent constraint. Treating all four as low confidence leads to the wrong recovery action.
Run the smallest useful experiment
The interactive lab below uses the three affine translations from the opening example. Each edge specifies how much a value changes when transported to the next node. The closure error is the sum around the oriented cycle. Zero means the offsets can arise from node values. A non-zero result means no exact gluing exists.
Close the triangle
Change any offset. Set C → A to −5 to make the loop close exactly. Values are synthetic.
The browser lab exposes one invariant. The companion Python artefact adds weighted least squares, cycle witnesses, anchor conflicts, ambiguity and a spectral stability proxy. It accepts a JSON model in which every directed edge states x_v − x_u = offset.
A positive exact-gluing result permits only the conclusion that the supplied scalar affine constraints are mutually satisfiable. A non-zero cycle witness identifies a structural conflict. A non-zero ambiguity dimension means the model lacks an absolute anchor for at least one component. A small stability margin warns that relative state is weakly constrained. None of these results establishes factual truth, causal validity, adequate coverage or moral authority.
#!/usr/bin/env python3
"""Gluing Assurance Record for scalar affine constraints on a graph.
Each directed edge u -> v encodes the local translation
x_v - x_u = offset
The analyser separates four questions:
1. obstruction: do translations close around every cycle and agree with anchors?
2. fit: what least-squares state best reconciles noisy constraints?
3. ambiguity: how many connected components remain unanchored?
4. stability: how strongly does the graph constrain relative state?
This is a small teaching implementation. It is not a general sheaf-cohomology
library and should not be used as the sole release control for consequential systems.
"""
from __future__ import annotations
from dataclasses import dataclass
import json
import math
import sys
from pathlib import Path
from typing import Any, Dict, Iterable, List, Mapping, MutableMapping, Sequence, Tuple
@dataclass(frozen=True)
class Edge:
u: str
v: str
offset: float
weight: float = 1.0
label: str = ""
@dataclass(frozen=True)
class Anchor:
node: str
value: float
weight: float = 1000.0
label: str = ""
def _parse_model(raw: Mapping[str, Any]) -> Tuple[List[str], List[Edge], List[Anchor]]:
nodes = [str(n) for n in raw.get("nodes", [])]
if not nodes:
raise ValueError("model.nodes must contain at least one node")
if len(nodes) != len(set(nodes)):
raise ValueError("model.nodes contains duplicates")
node_set = set(nodes)
edges: List[Edge] = []
for i, item in enumerate(raw.get("edges", [])):
u, v = str(item["u"]), str(item["v"])
if u not in node_set or v not in node_set:
raise ValueError(f"edge {i} references an unknown node")
if u == v:
raise ValueError(f"edge {i} is a self-loop; expand it as an explicit constraint")
weight = float(item.get("weight", 1.0))
if weight <= 0:
raise ValueError(f"edge {i} has non-positive weight")
edges.append(
Edge(
u=u,
v=v,
offset=float(item["offset"]),
weight=weight,
label=str(item.get("label", f"{u}->{v}")),
)
)
anchors: List[Anchor] = []
for i, item in enumerate(raw.get("anchors", [])):
node = str(item["node"])
if node not in node_set:
raise ValueError(f"anchor {i} references an unknown node")
weight = float(item.get("weight", 1000.0))
if weight <= 0:
raise ValueError(f"anchor {i} has non-positive weight")
anchors.append(
Anchor(
node=node,
value=float(item["value"]),
weight=weight,
label=str(item.get("label", f"anchor:{node}")),
)
)
return nodes, edges, anchors
def _components(nodes: Sequence[str], edges: Sequence[Edge]) -> Tuple[List[List[str]], Dict[str, int]]:
adjacency: Dict[str, List[str]] = {n: [] for n in nodes}
for edge in edges:
adjacency[edge.u].append(edge.v)
adjacency[edge.v].append(edge.u)
components: List[List[str]] = []
component_of: Dict[str, int] = {}
for start in nodes:
if start in component_of:
continue
cid = len(components)
stack = [start]
component: List[str] = []
component_of[start] = cid
while stack:
node = stack.pop()
component.append(node)
for nxt in adjacency[node]:
if nxt not in component_of:
component_of[nxt] = cid
stack.append(nxt)
components.append(component)
return components, component_of
def _cycle_witnesses(nodes: Sequence[str], edges: Sequence[Edge]) -> Tuple[Dict[str, float], List[Dict[str, Any]]]:
"""Assign tree potentials and report closure error on each non-tree edge."""
adjacency: Dict[str, List[Tuple[str, float, int]]] = {n: [] for n in nodes}
for index, edge in enumerate(edges):
# Traversing u -> v adds offset; traversing v -> u subtracts it.
adjacency[edge.u].append((edge.v, edge.offset, index))
adjacency[edge.v].append((edge.u, -edge.offset, index))
potentials: Dict[str, float] = {}
parent_edge: Dict[str, int] = {}
tree_edges: set[int] = set()
for root in nodes:
if root in potentials:
continue
potentials[root] = 0.0
stack = [root]
while stack:
node = stack.pop()
for nxt, delta, edge_index in adjacency[node]:
if nxt not in potentials:
potentials[nxt] = potentials[node] + delta
parent_edge[nxt] = edge_index
tree_edges.add(edge_index)
stack.append(nxt)
witnesses: List[Dict[str, Any]] = []
for index, edge in enumerate(edges):
if index in tree_edges:
continue
closure = potentials[edge.v] - potentials[edge.u] - edge.offset
witnesses.append(
{
"edge": edge.label or f"{edge.u}->{edge.v}",
"u": edge.u,
"v": edge.v,
"required_offset": edge.offset,
"implied_offset": potentials[edge.v] - potentials[edge.u],
"closure_error": closure,
}
)
return potentials, witnesses
def _anchor_witnesses(
components: Sequence[Sequence[str]],
component_of: Mapping[str, int],
potentials: Mapping[str, float],
anchors: Sequence[Anchor],
) -> List[Dict[str, Any]]:
by_component: Dict[int, List[Tuple[Anchor, float]]] = {i: [] for i in range(len(components))}
for anchor in anchors:
# The anchor implies a root value for its component.
implied_root = anchor.value - potentials[anchor.node]
by_component[component_of[anchor.node]].append((anchor, implied_root))
witnesses: List[Dict[str, Any]] = []
for cid, items in by_component.items():
if len(items) < 2:
continue
reference_anchor, reference_root = items[0]
for anchor, implied_root in items[1:]:
witnesses.append(
{
"component": cid,
"reference": reference_anchor.label,
"other": anchor.label,
"reference_implied_root": reference_root,
"other_implied_root": implied_root,
"closure_error": implied_root - reference_root,
}
)
return witnesses
def _solve_linear_system(matrix: List[List[float]], rhs: List[float], tolerance: float = 1e-12) -> List[float]:
"""Solve a dense square system using Gaussian elimination with pivoting."""
n = len(rhs)
augmented = [row[:] + [rhs[i]] for i, row in enumerate(matrix)]
for col in range(n):
pivot = max(range(col, n), key=lambda r: abs(augmented[r][col]))
if abs(augmented[pivot][col]) <= tolerance:
raise ValueError("normal equations are singular after gauge fixing")
if pivot != col:
augmented[col], augmented[pivot] = augmented[pivot], augmented[col]
pivot_value = augmented[col][col]
for j in range(col, n + 1):
augmented[col][j] /= pivot_value
for row in range(n):
if row == col:
continue
factor = augmented[row][col]
if abs(factor) <= tolerance:
continue
for j in range(col, n + 1):
augmented[row][j] -= factor * augmented[col][j]
return [augmented[i][n] for i in range(n)]
def _least_squares(
nodes: Sequence[str],
edges: Sequence[Edge],
anchors: Sequence[Anchor],
components: Sequence[Sequence[str]],
component_of: Mapping[str, int],
) -> Tuple[Dict[str, float], List[Dict[str, Any]], float, float]:
index = {node: i for i, node in enumerate(nodes)}
equations: List[Tuple[List[float], float, float, str, str]] = []
for edge in edges:
row = [0.0] * len(nodes)
row[index[edge.u]] = -1.0
row[index[edge.v]] = 1.0
equations.append((row, edge.offset, edge.weight, "edge", edge.label))
anchored_components = {component_of[a.node] for a in anchors}
for anchor in anchors:
row = [0.0] * len(nodes)
row[index[anchor.node]] = 1.0
equations.append((row, anchor.value, anchor.weight, "anchor", anchor.label))
# One gauge equation per unanchored component fixes only the arbitrary origin.
for cid, component in enumerate(components):
if cid in anchored_components:
continue
row = [0.0] * len(nodes)
row[index[component[0]]] = 1.0
equations.append((row, 0.0, 1.0, "gauge", f"gauge:{component[0]}"))
n = len(nodes)
normal = [[0.0 for _ in range(n)] for _ in range(n)]
target = [0.0 for _ in range(n)]
for row, value, weight, _, _ in equations:
for i in range(n):
if row[i] == 0:
continue
target[i] += weight * row[i] * value
for j in range(n):
if row[j] != 0:
normal[i][j] += weight * row[i] * row[j]
# Tiny diagonal regularisation handles isolated, gauge-fixed numerical cases.
for i in range(n):
normal[i][i] += 1e-12
solution_vector = _solve_linear_system(normal, target)
solution = {node: solution_vector[index[node]] for node in nodes}
residuals: List[Dict[str, Any]] = []
weighted_sum = 0.0
total_weight = 0.0
max_abs = 0.0
for row, value, weight, kind, label in equations:
if kind == "gauge":
continue
predicted = sum(coef * solution_vector[i] for i, coef in enumerate(row))
residual = predicted - value
residuals.append(
{
"kind": kind,
"label": label,
"required": value,
"predicted": predicted,
"residual": residual,
"weight": weight,
}
)
if kind == "edge":
weighted_sum += weight * residual * residual
total_weight += weight
max_abs = max(max_abs, abs(residual))
rms = math.sqrt(weighted_sum / total_weight) if total_weight else 0.0
return solution, residuals, rms, max_abs
def _jacobi_eigenvalues(matrix: Sequence[Sequence[float]], tolerance: float = 1e-12) -> List[float]:
"""Eigenvalues of a small real symmetric matrix via Jacobi rotations."""
n = len(matrix)
if n == 0:
return []
a = [list(row) for row in matrix]
max_iterations = max(50, 20 * n * n)
for _ in range(max_iterations):
p, q, largest = 0, 0, 0.0
for i in range(n):
for j in range(i + 1, n):
value = abs(a[i][j])
if value > largest:
p, q, largest = i, j, value
if largest < tolerance:
break
app, aqq, apq = a[p][p], a[q][q], a[p][q]
angle = 0.5 * math.atan2(2.0 * apq, aqq - app)
c, s = math.cos(angle), math.sin(angle)
for k in range(n):
if k in (p, q):
continue
akp, akq = a[k][p], a[k][q]
a[k][p] = a[p][k] = c * akp - s * akq
a[k][q] = a[q][k] = s * akp + c * akq
a[p][p] = c * c * app - 2.0 * s * c * apq + s * s * aqq
a[q][q] = s * s * app + 2.0 * s * c * apq + c * c * aqq
a[p][q] = a[q][p] = 0.0
return sorted(a[i][i] for i in range(n))
def _stability_margin(nodes: Sequence[str], edges: Sequence[Edge], tolerance: float) -> float:
"""Return the smallest positive eigenvalue of the weighted scalar graph Laplacian."""
index = {node: i for i, node in enumerate(nodes)}
n = len(nodes)
laplacian = [[0.0 for _ in range(n)] for _ in range(n)]
for edge in edges:
i, j, w = index[edge.u], index[edge.v], edge.weight
laplacian[i][i] += w
laplacian[j][j] += w
laplacian[i][j] -= w
laplacian[j][i] -= w
positive = [ev for ev in _jacobi_eigenvalues(laplacian) if ev > tolerance]
return min(positive) if positive else 0.0
def analyse_model(
raw: Mapping[str, Any],
*,
tolerance: float = 1e-9,
review_threshold: float = 0.25,
) -> Dict[str, Any]:
nodes, edges, anchors = _parse_model(raw)
components, component_of = _components(nodes, edges)
potentials, cycle_witnesses = _cycle_witnesses(nodes, edges)
anchor_witnesses = _anchor_witnesses(components, component_of, potentials, anchors)
all_obstructions = [abs(w["closure_error"]) for w in cycle_witnesses]
all_obstructions.extend(abs(w["closure_error"]) for w in anchor_witnesses)
max_obstruction = max(all_obstructions, default=0.0)
exactly_gluable = max_obstruction <= tolerance
solution, residuals, rms_residual, max_residual = _least_squares(
nodes, edges, anchors, components, component_of
)
anchored_components = {component_of[a.node] for a in anchors}
ambiguity_dimension = sum(1 for cid in range(len(components)) if cid not in anchored_components)
stability_margin = _stability_margin(nodes, edges, tolerance)
if not exactly_gluable and max_obstruction > review_threshold:
decision = "reject_structural_obstruction"
elif not exactly_gluable:
decision = "review_near_consistent"
elif ambiguity_dimension > 0:
decision = "insufficient_boundary"
elif stability_margin <= tolerance:
decision = "review_fragile_or_disconnected"
else:
decision = "accept_for_encoded_scope"
return {
"gluing_assurance_record": {
"exactly_gluable": exactly_gluable,
"max_obstruction": max_obstruction,
"weighted_rms_residual": rms_residual,
"max_fitted_residual": max_residual,
"ambiguity_dimension": ambiguity_dimension,
"stability_margin": stability_margin,
"decision": decision,
},
"best_fit_state": solution,
"cycle_witnesses": cycle_witnesses,
"anchor_witnesses": anchor_witnesses,
"fitted_residuals": residuals,
"model_scope": {
"nodes": len(nodes),
"edges": len(edges),
"anchors": len(anchors),
"components": len(components),
},
"limitations": [
"Only scalar affine edge translations are supported.",
"Consistency is relative to the supplied nodes, constraints, weights, and anchors.",
"A zero obstruction does not establish factual truth, causal correctness, or adequate coverage.",
],
}
DEMO_MODEL: Dict[str, Any] = {
"nodes": ["A", "B", "C"],
"edges": [
{"u": "A", "v": "B", "offset": 2.0, "label": "A to B"},
{"u": "B", "v": "C", "offset": 3.0, "label": "B to C"},
{"u": "C", "v": "A", "offset": -4.0, "label": "C to A"},
],
"anchors": [{"node": "A", "value": 0.0, "weight": 1000.0, "label": "A origin"}],
}
def _main(argv: Sequence[str]) -> int:
if len(argv) > 2:
print(f"usage: {Path(argv[0]).name} [model.json]", file=sys.stderr)
return 2
if len(argv) == 2:
raw = json.loads(Path(argv[1]).read_text(encoding="utf-8"))
else:
raw = DEMO_MODEL
result = analyse_model(raw)
print(json.dumps(result, indent=2, sort_keys=True))
return 0
if __name__ == "__main__":
raise SystemExit(_main(sys.argv))
Run with python paper-158-sheaf-consistency-lab.py for the built-in triangle, or pass a JSON file. The implementation uses only the Python standard library.
Input schema, invariants and decision meanings
The top-level JSON object contains nodes, edges and optional anchors. Every edge has u, v, offset, optional weight and optional label. An anchor fixes one node to an absolute value.
The invariant is explicit: for every edge, the candidate state should satisfy x_v − x_u = offset. The cycle analyser constructs a spanning forest and checks each non-tree edge against the offset implied by the tree. The least-squares stage distributes unavoidable mismatch. The ambiguity dimension counts connected components without an anchor. The stability margin is the smallest positive eigenvalue of the weighted scalar graph Laplacian.
accept_for_encoded_scope means exact closure, adequate anchoring and a positive stability margin under this model. insufficient_boundary means the relative constraints glue but do not fix an absolute state. review_near_consistent means a small non-zero obstruction remains. reject_structural_obstruction means the closure defect exceeds the declared review threshold.
Use the result to choose the repair
The practical gate is not “score above threshold”. It is a branching decision. When obstruction is non-zero, identify the smallest witness cycle and inspect its local claims and translations. When obstruction is zero but ambiguity remains, add an anchor or enrich the overlap. When the section is unique but unstable, collect an independent measurement or reduce the action’s irreversibility. Only when the encoded state is compatible, sufficiently determined and stable should the system proceed within its declared authority.
Proceed within scope
Obstruction is zero, ambiguity is decision-irrelevant, stability is adequate and the action is reversible.
Strengthen evidence
The state glues, but consequence is high. Require independent paths, tighter anchors, readback and recovery.
Repair the model
Residual or ambiguity is localised and consequence is low. Fix translations, coverage or anchors before retrying.
Block the action
A structural obstruction survives and the action is hard to reverse. Do not average through the conflict.
Global sections as consistent states, sheaf Laplacians and consistency radii are published constructions.[5][4] Recent work applies cellular sheaves to heterogeneous graph learning and distributed task solvability.[10][11] The GAR, its four-field release gate and the maintenance example are practitioner synthesis. They require domain validation before operational use.
sequenceDiagram participant Q as Question participant M as Mechanism participant E as Evidence participant D as Decision Q->>M: The map that moved the bridge M->>E: From patches to a sheaf E-->>M: compare rival explanations E->>D: Prove the reports inhabit one decision-relevant state D-->>Q: revise scope or act
Prove the reports inhabit one decision-relevant state
A local report is easy to accept because it arrives with detail. A component can show a timestamp, a confidence score, an explanation and a valid signature. Another component can do the same. Yet the decision-maker does not act on those reports separately. It acts on the state they appear to describe together. The practical question is therefore not whether each source looks respectable. It is whether the sources can inhabit one state after their meanings, times, identities and authorities have been translated onto shared overlaps.
Do not globalise information merely because every pair appears to agree. Pairwise agreement may be checked in different coordinate systems, at different cutoffs or against different versions of authority. It can also be vacuous when the overlap carries too little information. A reliable globalisation decision needs a declared candidate boundary, explicit translation maps, loop closure, enough anchors to remove consequential ambiguity and a stability check suited to the cost of acting.
Begin with the decision, not the database
Suppose a maintenance system must decide whether to release a machine. Start by writing the release proposition in a typed form: machine identity, installed part, inspection result, approver, approval version, valid interval and requested action. This statement defines the candidate global section. The local spaces are then chosen because they supply or constrain one of those fields. The inventory service need not expose its entire schema. The inspection tool need not be treated as an oracle. Each contributes only the section and restriction maps required by the decision.
This reverses a common integration habit. Teams often begin with available data, merge fields and then ask what the combined record means. A sheaf-informed design begins with the global state that would justify action and asks what local evidence would have to agree for that state to exist. The design thereby makes missing overlaps visible. If the inspection receipt has no binding to machine identity, the system lacks a necessary map. If approval is tied to a work-order version but the action contract carries only a work-order number, the apparent join discards the very distinction that protects the decision.
Typed database mappings already show why migrations should preserve structure rather than merely move values.[8] The same discipline applies here, but the target is not a universal enterprise ontology. The target is a decision-sized consistency model. It should include exactly the distinctions whose loss could change the action, no fewer and no more.
Define, translate, close, determine, stress, then act. Define the candidate global state and its boundary. Translate every local section onto each decision-relevant overlap. Close independent routes around cycles. Determine whether more than one global state remains possible. Stress the result under plausible perturbations, stale versions and missing sources. Act only within the authority and reversibility represented by the model.
Choose the repair from the diagnosis
The four fields in the Gluing Assurance Record are deliberately not interchangeable. An obstruction asks whether the encoded descriptions can be true together. Ambiguity asks how many global states remain compatible with them. Instability asks whether small local changes can produce large global changes. Authority asks whether the resulting state may support this action. A system that treats all four as “low confidence” cannot choose a principled repair.
When a cycle obstruction appears, inspect the smallest witness rather than averaging the entire network. One translation may use a different unit, one assertion may refer to the wrong subject or one cache may preserve an obsolete permission. The witness cycle narrows the search to the relations that cannot jointly hold. Database consistency research makes a related point: global consistency of overlapping data collections is not reducible to arbitrary local checks, and structural conditions determine when local consistency is sufficient.[9]
When obstruction is zero but ambiguity remains, a new measurement may be more useful than a better optimiser. Add an anchor, widen an overlap or make the decision less specific. If two possible installed parts fit all current reports, no amount of numerical smoothing can manufacture identification. The correct output is not a confident guess. It is a record of what additional distinction would collapse the remaining alternatives.
When the state is unique but unstable, seek an independent path or reduce consequence. A nearly disconnected network can transmit enough constraints to identify a solution while making that solution extremely sensitive to one weak edge. The spectral margin in the lab is only a scalar proxy, but it expresses the operational intuition: a state held together by one fragile translation deserves a different release rule from a state supported by several independent overlaps.
When the state is coherent, determined and stable but authority is absent, stop anyway. Mathematical gluing does not confer permission. A valid section over facts and receipts can coexist with an invalid action because the actor lacks the capability, purpose or temporal entitlement required to use those facts. Consistency is a property of the encoded descriptions; release is a governed decision.
Three teams enter a review. Inventory says part P-17 is installed. Inspection says P-17 passed. Governance says work order W-42 is approved. In the old meeting, three green indicators produce a release. In the gluing meeting, the chair asks for the overlap maps. Inventory binds P-17 to machine M-8 at version 12. Inspection binds its test to M-8 at version 11. Governance approves W-42 version 12, but W-42 version 12 replaced P-17 with P-19. Every local statement may be accurate in its own context. There is no section that assigns one installed part and one work-order version across all three contexts.
The repair is not “ask the model again”. The team either re-inspects the version-12 configuration, rolls the work order back under a new authorised action or withholds release. The loop changed the meeting from a vote over green lights into a test of whether the lights describe the same world.
The strongest boundary: coherence is not truth
A perfectly glued map can still be wrong. Three sensors may share the same calibration fault. Three services may copy a false master record. A human team may reach coherent agreement through a common but mistaken assumption. Sheaf consistency detects incompatibility relative to supplied spaces and maps. It does not prove that the spaces represent the world adequately, that the maps are causally justified or that an omitted variable is harmless.
This boundary is not a minor disclaimer. It determines the assurance architecture. A gluing gate should sit beside, not replace, provenance checks, independent measurement, causal validation, adversarial testing and outcome readback. The method is most valuable where local descriptions are heterogeneous and their joins carry risk. It is less informative when all sources are generated by one pipeline, when the cover has no meaningful overlaps, when the relevant relation is intentionally non-deterministic or when the global state changes faster than the observations can be aligned.
There is also a mathematical limit. A chosen cohomological test may expose a particular obstruction without being complete for every form of contextuality. Non-vanishing cohomology can witness contextuality in the Abramsky programme, but vanishing of that obstruction does not universally prove a global model exists.[7] In engineered systems, the analogous discipline is to state which defect the test can reveal, then keep rival generators for false reassurance.
Do not use the scalar affine lab as a generic truth engine, a consciousness test, a moral-status score or a substitute for domain modelling. It assumes fixed nodes, additive edge translations, declared weights and a snapshot-like state. Nonlinear, probabilistic, temporal or higher-dimensional systems need richer stalks, maps and diagnostics. The teaching artefact is useful precisely because its assumptions are visible.
A hypothesis worth testing
The practitioner hypothesis is that gluing debt predicts integration failure better than pairwise agreement alone. Gluing debt is the unresolved combination of missing translations, non-closing cycles, decision-relevant ambiguity and weak stability at the moment a global state is asserted. It is not a theorem and it should not be converted into a universal score.
The smallest useful study would take a set of synthetic or historically replayable compound-system decisions. For each decision, record pairwise agreement, the GAR fields and whether replay reveals identity mismatch, stale authority, inconsistent state or unstable reconstruction. The hypothesis gains support if GAR defects forecast these failures after controlling for ordinary confidence and source count. It weakens if pairwise checks perform equally well, if the proposed witnesses do not localise repair or if most incidents arise outside the encoded boundary.
A rival explanation is simple data quality: the GAR may work only because it counts missing or inconsistent fields more carefully. To separate the accounts, compare it with a strong schema-validation baseline using the same inputs. Another rival is graph density: better-connected systems may both score well and fail less for reasons unrelated to sheaf structure. Match or model connectivity. Do not apply the hypothesis to domains where no stable candidate global state can be named. The first implementation should be a shadow-mode gate that records witnesses and decisions without blocking live work.
Observation that would strengthen it: structural witnesses repeatedly identify the relation whose correction resolves replayed failures. Result that would weaken it: witnesses are unstable across equivalent encodings or add no predictive value beyond a strong typed-schema baseline. Rival explanation: common-cause data quality or graph connectivity. Smallest implementation: one decision type, three to six local sources, explicit versioned overlaps and offline replay.
What should change on Monday
Before a human or machine combines local outputs into a consequential claim, require a gluing record. Name the candidate world state. Show how each source restricts to shared fields. Preserve version, time, subject and authority in those maps. Test independent paths and cycles. Report ambiguity separately from residual. Scale the stability and recovery burden with irreversibility. Retain the smallest witness whenever the gate refuses a global state.
This changes the release question. Instead of asking, “Do the services agree?” ask, “Is there one decision-relevant state whose restrictions are these reports?” Instead of asking, “Can the discrepancy be averaged?” ask, “Does the discrepancy reveal a broken translation, a missing anchor or ordinary noise?” Instead of asking, “Is the score high enough?” ask, “What conclusion does this exact diagnostic permit, and what remains outside its scope?”
The bridge in the opening case did not move. The coordinate system did. The failure occurred because the join erased that fact. Sheaf thinking makes the seam part of the model. The decision this changes is whether local evidence may be promoted into a global state at all. Promote it only when the translations close, the remaining ambiguity cannot change the decision, the state is stable enough for the consequence and the action remains within authority.