Sheaf Descent & Gluing
Descent is the mechanism by which JuGeo assembles local judgments — proved separately on pieces of a covering family — into a single global judgment on the covered object. When descent fails, it produces an obstruction class.
The Descent Condition
Let \(\mathcal{F}\) be the judgment sheaf on the semantic site \((\mathcal{C}, J)\), and let \(\{U_i \to U\}_{i \in I}\) be a covering family. The descent condition states that the natural map
is an isomorphism. In other words: a section (judgment) over \(U\) exists if and only if sections over each \(U_i\) exist and they agree on all pairwise intersections \(U_i \times_U U_j\). When the condition holds, global data can be assembled from local data; when it fails, the mismatch on intersections is recorded as a first cohomology class \([c] \in H^1\).
In the codebase setting this means: to prove a property of a module, JuGeo proves it for each function and class in the module (the covering family), then checks that the proofs are compatible at the shared interfaces (the intersections). Compatibility is checked by verifying that the type signatures and effect annotations at call-sites match.
Local and Global Sections
JuGeo exposes the sheaf-theoretic concepts as Python classes:
-
LocalSection— a judgment \(J \in \mathcal{F}(U_i)\) for a single element of the covering family. Carries the coordinate \(U_i\), the formula, and the evidence bundle. -
GluingData— the collection of all local sections together with the compatibility evidence at pairwise intersections \(U_i \times_U U_j\). This is the input to the descent computation. -
GlobalSection— the assembled judgment \(J \in \mathcal{F}(U)\), produced when descent succeeds. Its trust is the meet of all local section trusts.
from jugeo.geometry.site import Coordinate, CoordinateKind
from jugeo.geometry.covers import Cover
from jugeo.geometry.descent import GluingData, LocalSection
module = Coordinate(("mymod",), CoordinateKind.MODULE)
left = Coordinate(("mymod", "validate"), CoordinateKind.FUNCTION)
right = Coordinate(("mymod", "transform"), CoordinateKind.FUNCTION)
cover = Cover(
target=module,
patches=(left, right),
overlaps=((left.key, right.key),),
provenance=("docs",),
)
gluing = GluingData.from_cover(
cover,
{
left.key: {"pure": True, "throws": False},
right.key: {"pure": True, "throws": False},
},
)
print(gluing.patch_count()) # 2
print(gluing.verify_all_overlaps()[0].status) # OverlapStatus.SATISFIED
local = LocalSection(coordinate=left.key, judgment_data={"pure": True}, trust_level=0.9)
print(local.summary())
Gluing Data
The GluingData object encapsulates everything needed for the
descent computation. It records:
- The cover — the list of coordinates \(\{U_i\}\)
- The local sections — one per cover element
- The intersection data — for each pair \((i, j)\), the restriction of section \(i\) to \(U_i \times_U U_j\) and the restriction of section \(j\) to the same intersection
- The compatibility matrix — a boolean matrix indicating which pairs are compatible
When compatibility fails at a pair \((i, j)\), the mismatch is recorded as
an IntersectionConflict. The set of all conflicts is exactly the
data of a 1-cochain in the Čech complex, and if it is a 1-cocycle
(the coboundary vanishes), it represents a genuine obstruction in \(H^1\).
See the Obstructions page for the full
cohomological treatment.
The Four Descent Strategies
JuGeo provides four configurable strategies for running descent. Each represents a different trade-off between completeness, speed, and resource use.
Eager
Proves all local sections in parallel before checking compatibility. Fast when all sections succeed; wastes work if early failures are common.
Exhaustive
Tries every possible subset of the cover until descent succeeds. Complete but exponential in the worst case. Use only on small covers.
Iterative
Proves sections one at a time, checking compatibility after each. Stops early on the first failure and reports the conflict immediately.
Optimistic
Assumes compatibility and assembles a tentative global section first. Validates afterward. Fastest when compatibility holds; rolls back on failure.
Default strategy. The default is ITERATIVE for interactive
use (where fast feedback matters) and EAGER for CI pipelines (where full
parallelism is desirable). Set the strategy via DescentEngine(strategy=...)
or the JUGEO_DESCENT_STRATEGY environment variable.
Python Examples
Running descent end-to-end:
from jugeo.geometry.descent import (
DescentConfiguration,
DescentEngine,
DescentStrategy,
)
engine = DescentEngine(
configuration=DescentConfiguration(
strategy=DescentStrategy.EAGER,
record_log=False,
)
)
report = engine.run(
cover,
{
left.key: {"pure": True},
right.key: {"pure": True},
},
)
print(report.success) # True
print(report.glued_section) # {'pure': True}
Inspecting local sections produced during descent:
print(report.target) # mymod
print(report.local_sections) # raw local data by patch
print(report.obstructions) # empty tuple when gluing succeeds
rich_result = engine.attempt_descent(
cover,
{
left.key: {"pure": True},
right.key: {"pure": False},
},
)
if rich_result.is_failure:
obstruction = rich_result.unwrap_obstruction()
print(obstruction.violation_count)
print(obstruction.violated_pairs())
Descent Failure and Obstructions
When descent fails, JuGeo does not simply report an error. Instead, it computes the obstruction data and classifies it:
Conflict collection
All pairwise intersection failures are gathered into a 1-cochain \(c \in C^1(\mathcal{U}, \mathcal{F})\).
Cocycle check
JuGeo checks whether \(\delta c = 0\) in \(C^2\). If so, \(c\) represents a class in \(H^1\) — a genuine global obstruction. If not, the conflict is resolvable by reordering the cover.
Obstruction classification
The obstruction is classified as H⁰ (missing local section), H¹ (compatibility failure), H² (higher coherence failure), or H∞ (undecidable). See Obstructions.
Repair suggestion
For each obstruction, JuGeo suggests a repair: a code change that, if applied, would make the local sections compatible. Repairs are ranked by estimated effort and reported with source locations.
H∞ obstructions. Some obstructions are classified as H∞ — this means the compatibility condition reduces to an undecidable problem (e.g., halting for general recursive functions). JuGeo will report the obstruction with trust NONE and suggest adding explicit annotations or switching to a FORMAL evidence channel.