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

Definition 3.1 — Sheaf Descent Condition
$$\mathcal{F}(U) \;\xrightarrow{\;\sim\;}\; \varprojlim\Bigl(\prod_{i} \mathcal{F}(U_i) \;\rightrightarrows\; \prod_{i,j} \mathcal{F}(U_i \times_U U_j)\Bigr)$$

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:

python
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:

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

Eager

Proves all local sections in parallel before checking compatibility. Fast when all sections succeed; wastes work if early failures are common.

EXHAUSTIVE

Exhaustive

Tries every possible subset of the cover until descent succeeds. Complete but exponential in the worst case. Use only on small covers.

ITERATIVE

Iterative

Proves sections one at a time, checking compatibility after each. Stops early on the first failure and reports the conflict immediately.

OPTIMISTIC

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:

python
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:

python
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:

1
Conflict collection

All pairwise intersection failures are gathered into a 1-cochain \(c \in C^1(\mathcal{U}, \mathcal{F})\).

2
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.

3
Obstruction classification

The obstruction is classified as H⁰ (missing local section), H¹ (compatibility failure), H² (higher coherence failure), or H∞ (undecidable). See Obstructions.

4
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.