Core Concepts
JuGeo rests on a single geometric insight: proofs are not terms, they are sections of sheaves over programs. This page develops the mathematical foundations — from the definition of a judgment to cohomological obstruction theory — that underpin every feature of the library.
1. The Central Idea
Classical proof theory assigns proofs a term structure: a derivation tree whose nodes are inference rules. JuGeo takes a different stance. A proof obligation over a piece of code is not a single term — it is a geometric object living at a coordinate in the program's semantic space. When the program evolves, the obligation transforms. When the program branches, the obligation splits. This is the language of sheaves.
A judgment is a 4-tuple
\[ \mathcal{J} \;=\; (\mathbb{S}_{\mathrm{top}},\; \mathbb{P}_{\mathrm{str}},\; \mathbb{C}_{\mathrm{spec}},\; \mathbb{G}_{\mathrm{eval}}) \]where each component is defined as follows.
| Symbol | Name | Type | Description |
|---|---|---|---|
| \(\mathbb{S}_{\mathrm{top}}\) | Semantic Topos | Site + Grothendieck topology | The site, Grothendieck topology, sheaf topos, and internal logic. Subsumes the old coordinate \(c\) and formula \(\varphi\). |
| \(\mathbb{P}_{\mathrm{str}}\) | Proof Structure | Contexts, types, terms | Contexts, types, terms, and derivation trees. Subsumes the old assumptions \(A\) and evidence \(E\). |
| \(\mathbb{C}_{\mathrm{spec}}\) | Cohomological Spectrum | \(H^*(\mathcal{S}_P;\, \mathcal{F}_J)\) | Covers, Čech complex, cohomology groups, and obstruction classes. Subsumes the old obstruction class \(O\) and budget \(B\). |
| \(\mathbb{G}_{\mathrm{eval}}\) | Graded Evaluation | \(\mathfrak{T}\) + quantale | Grade semiring, quantale, evaluation functor, and trust algebra. Subsumes the old trust level \(T\) and proof term \(\Pi\). |
The coordinate \(c\) is the crucial departure from classical proof theory. In standard Hoare logic, a triple \(\{P\}\, S\, \{Q\}\) has no notion of where in a larger codebase it lives or how it relates geometrically to neighboring triples. JuGeo situates every judgment in a site \(\mathcal{S}_P\), making restriction, gluing, and transport into well-defined mathematical operations rather than informal reuse patterns.
The key operations on judgments mirror those on sheaf sections:
- Restriction \(J|_U\): project a judgment to a sub-coordinate \(U \hookrightarrow c\).
- Gluing \(\mathrm{glue}(J_1, \ldots, J_n)\): assemble compatible local judgments into a global one.
- Transport \(f^* J\): pull back a judgment along a morphism \(f : c' \to c\) (inlining, specialization).
- Challenge \(\partial J\): lower the trust level and require re-verification.
- Escalate \(\uparrow J\): route to a higher-authority channel for re-evaluation.
2. Semantic Sites
A semantic site is a small category \(\mathcal{S}_P\) equipped with a Grothendieck topology \(J_P\). The objects of \(\mathcal{S}_P\) are the coordinates of program \(P\); the morphisms model how one coordinate relates to another via scope nesting, control flow, or module inclusion. The topology specifies which families of morphisms constitute covers — enough local data to reconstruct global behavior.
Let \(P\) be a Python program. The semantic site of \(P\) is the pair \(\bigl(\mathcal{S}_P,\, J_P\bigr)\) where:
- \(\Ob(\mathcal{S}_P)\) is the set of coordinates of \(P\),
- morphisms are generated by the four primitive relations below, and
- \(J_P\) is the Grothendieck topology generated by the four covering families below.
Objects — Program Coordinates
A coordinate is any syntactically delimited region of \(P\). The taxonomy is:
Morphisms — Four Primitive Relations
| Morphism type | Notation | Meaning |
|---|---|---|
| Restriction | \(\iota : U \hookrightarrow V\) | Sub-coordinate inclusion: a branch arm inside a function, a loop body inside a branch, etc. |
| Scope nesting | \(\sigma : \text{Scope}(f,d) \to \text{Scope}(f,d-1)\) | Inner scope included in outer scope; assumptions flow outward, obligations inward. |
| Transport / call | \(\tau_g : \text{Function}(f) \to \text{Function}(g)\) | A call from \(g\) to \(f\); pulls back the postcondition of \(f\) as a local fact in \(g\). |
| Refinement | \(\rho : c_{\text{refined}} \to c\) | A loop unrolling, inline expansion, or specification strengthening that creates a tighter coordinate. |
Covering Families — The Grothendieck Topology
A family \(\{f_i : U_i \to U\}_{i \in I}\) is a covering sieve of \(U\) in \(J_P\) when it belongs to one of four standard generating classes:
| Cover type | Generator | Semantics |
|---|---|---|
| Control-flow cover | \(\{\text{Branch}(f,k)\}_{k}\) | The branches of an if/match together cover the function body: every execution path is witnessed. |
| Scope cover | \(\{\text{Scope}(f,d)\}_{d}\) | Nested scopes cover the function: a fact valid at every nesting depth holds for the whole function. |
| Module cover | \(\{\text{Class}(cls_i)\}_i\) | Classes of a module cover the module: module-level properties are assembled from per-class properties. |
| Temporal cover | \(\{\text{Loop}(f,k,n)\}_{n}\) | Unrolled loop iterations cover the loop body: an inductive argument assembles infinitely many local sections into a loop invariant. |
The Grothendieck Axioms
The covering sieves must satisfy three axioms to form a Grothendieck topology on \(\mathcal{S}_P\):
The Sheaf Condition on Specification Functors
A specification functor \(\mathcal{F} : \mathcal{S}_P^{\mathrm{op}} \to \mathbf{Set}\) assigns to each coordinate a set of local specifications. It is a sheaf (equivalently: local specifications glue to global ones) iff the following equalizer diagram is exact for every covering sieve \(\{U_i \to U\}\):
In plain terms: a collection of local specifications \(\{s_i \in \mathcal{F}(U_i)\}\) that agree on all pairwise overlaps \(U_i \times_U U_j\) is the restriction of a unique global specification \(s \in \mathcal{F}(U)\). This is exactly what program verification needs: branch-level postconditions that agree on shared state glue into a function-level postcondition.
from jugeo.geometry.site import Coordinate, CoordinateKind, build_site
base = Coordinate(("mypackage",), CoordinateKind.MODULE)
parse_fn = Coordinate(("mypackage", "parse"), CoordinateKind.FUNCTION)
site = build_site([base, parse_fn])
print(site.coordinate_count())
print(site.morphism_count())
print([obj.name for obj in site.objects()])
3. Sheaf Descent
Descent is the process of assembling a global judgment from a compatible family of local judgments. Given a covering family \(\{U_i \to U\}_{i \in I}\) and local judgments \(J_i\) on each \(U_i\), descent asks: do the \(J_i\) agree on all pairwise overlaps, and if so, is there a unique global \(J\) restricting to each \(J_i\)?
A family \(\{J_i\}_{i \in I}\) of local judgments satisfies the descent condition when
\[ J_i\big|_{U_i \cap U_j} \;=\; J_j\big|_{U_i \cap U_j} \qquad \forall\, i,j \in I. \]When the descent condition holds, there exists a unique global judgment \(J\) on \(U\) — its gluing} — such that \(J|_{U_i} = J_i\) for every \(i\).
Diagram: Descent for a Branching Function
Four Descent Strategies
JuGeo implements four strategies for orchestrating the descent computation, trading off coverage guarantees against resource consumption:
COPILOT_SUGGESTED. Escalate to solvers only when a challenge
is issued. Best throughput for large codebases with few real obstructions.
from jugeo.geometry.descent import DescentEngine, DescentStrategy
engine = DescentEngine()
print(type(engine).__name__)
print([strategy.name for strategy in DescentStrategy])
4. The Trust Algebra
Not all evidence is equal. A runtime test witnessing a property once is less reliable than a formal proof that holds for all inputs. JuGeo makes this precise with a trust algebra — a partially ordered monoid with operations for combining, promoting, and challenging trust annotations.
The trust algebra is the 6-tuple
\[ \mathfrak{T} \;=\; \bigl(\mathcal{E}_{\mathrm{adm}},\; \preceq,\; \oplus,\; \ominus,\; \uparrow_\pi,\; \downarrow_\chi\bigr) \]where:
- \(\mathcal{E}_{\mathrm{adm}}\) is the set of admissible trust levels (a 7-element chain, see below),
- \(\preceq\) is the partial order on trust levels (\(\preceq\,\) is total on \(\mathcal{E}_{\mathrm{adm}}\)),
- \(\oplus : \mathcal{E}_{\mathrm{adm}} \times \mathcal{E}_{\mathrm{adm}} \to \mathcal{E}_{\mathrm{adm}}\) is the conservative join (trust combination),
- \(\ominus : \mathcal{E}_{\mathrm{adm}} \times \mathcal{E}_{\mathrm{adm}} \to \mathcal{E}_{\mathrm{adm}}\) is trust subtraction (challenge response),
- \(\uparrow_\pi\) is promotion along evidence \(\pi\) (trust upgrade with a witness), and
- \(\downarrow_\chi\) is demotion by challenge \(\chi\) (trust downgrade on counter-evidence).
The Seven Trust Levels
| Level | Constant | Numeric | Meaning | Channel |
|---|---|---|---|---|
| CONTRADICTED | T_⊥ |
0 | A counter-example was found; the claim is false. | Any |
| UNVERIFIED | T_? |
1 | No evidence collected yet. Initial state of every judgment. | — |
| COPILOT_SUGGESTED | T_cs |
2 | An LLM copilot has proposed a proof sketch; not yet validated. | COPILOT |
| ORACLE_PROPOSED | T_op |
3 | A trusted oracle (external service) asserts the claim. | ORACLE |
| RUNTIME_WITNESSED | T_rw |
4 | Observed to hold across collected runtime traces (probabilistic). | RUNTIME |
| SOLVER_DISCHARGED | T_sd |
5 | SMT/SAT solver returned UNSAT with a checkable certificate. | SOLVER |
| VERIFIED_PROOF | T_⊤ |
6 | Machine-checked proof term accepted by a proof assistant (Lean 4). | FORMAL_PROOF |
Algebra Operations
Conservative Join \(\oplus\)
Combining two trust levels yields the minimum — trust is only as strong as the weakest link:
\[ T_a \oplus T_b \;=\; \min_{\preceq}(T_a,\, T_b). \]Promotion \(\uparrow_\pi\)
Promotion upgrades trust when a new evidence object \(\pi\) is provided. Promotion is bounded by the trust ceiling of the channel that produced \(\pi\):
\[ \uparrow_\pi (T) \;=\; \begin{cases} \min\bigl(\mathrm{ceil}(\mathrm{ch}(\pi)),\; T_{\text{new}}\bigr) & \text{if } \pi \text{ validates } \varphi, \\ T & \text{otherwise.} \end{cases} \]Demotion \(\downarrow_\chi\)
When a challenge \(\chi\) (a counter-example candidate, a failing test, a conflicting oracle report) is issued against a judgment at trust level \(T\):
\[ \downarrow_\chi (T) \;=\; \begin{cases} T_\bot & \text{if } \chi \text{ is a valid counter-example,} \\ T_? & \text{if } \chi \text{ invalidates prior evidence (but no counter-example found),} \\ T & \text{if } \chi \text{ is rebutted.} \end{cases} \]The Three Laws
The trust algebra \(\mathfrak{T}\) satisfies:
Law 1 — No silent promotion. Trust cannot increase without explicit evidence:
\[ \nexists\, \text{operation } f : \mathcal{E}_{\mathrm{adm}} \to \mathcal{E}_{\mathrm{adm}} \text{ such that } f(T) \succ T \text{ without a witness.} \]Law 2 — Conservative join. Composition never exceeds the weaker component:
\[ \forall\, T_a, T_b \in \mathcal{E}_{\mathrm{adm}}: \quad T_a \oplus T_b \preceq T_a \;\text{ and }\; T_a \oplus T_b \preceq T_b. \]Law 3 — Challenge conservativity. A successful rebuttal of a challenge restores at most the original trust level:
\[ T' = \uparrow_\rho (\downarrow_\chi (T)) \preceq T \qquad \text{for all challenges } \chi \text{ and rebuttals } \rho. \]from jugeo.evidence.trust import TrustLevel, TrustAlgebra
T = TrustAlgebra()
combined = T.join(TrustLevel.RUNTIME_WITNESSED, TrustLevel.SOLVER_DISCHARGED)
print(combined)
print(T.promote(TrustLevel.COPILOT_SUGGESTED, "solver witness"))
print(T.demote(TrustLevel.SOLVER_DISCHARGED, TrustLevel.RUNTIME_WITNESSED))
5. Evidence Channels
An evidence channel is a named source of proof evidence, equipped with a jurisdiction (the class of properties it can handle), a trust ceiling (the maximum trust level it can award), and a cost model. JuGeo ships six built-in channels and supports third-party channel plugins.
An evidence channel is a triple \(\mathrm{Ch} = (\mathcal{J}, \tau_\mathrm{ceil}, \mathcal{C})\) where:
- \(\mathcal{J} \subseteq \text{Formula}\) is the channel's jurisdiction — the set of formulas it is authorised to discharge,
- \(\tau_\mathrm{ceil} \in \mathcal{E}_{\mathrm{adm}}\) is the trust ceiling, and
- \(\mathcal{C} : \text{Formula} \to \mathbb{R}_{\ge 0}^3\) is the cost model mapping formulas to expected \((t, \$, q)\) tuples.
⊢ φ@jugeo hintsChannel Routing
JuGeo's router maps each formula \(\varphi\) to the cheapest channel whose jurisdiction contains \(\varphi\) and whose trust ceiling meets the required trust level:
\[ \mathrm{route}(\varphi, T_\mathrm{req}) \;=\; \arg\min_{\mathrm{Ch}} \mathcal{C}_\mathrm{Ch}(\varphi) \;\text{subject to}\; \varphi \in \mathcal{J}_\mathrm{Ch} \;\text{ and }\; T_\mathrm{ceil}(\mathrm{Ch}) \succeq T_\mathrm{req}. \]6. Cohomological Obstructions
When descent fails — when local judgments do not agree on overlaps — the failure is not discarded. Instead it is captured as a cohomological obstruction: an element of a sheaf cohomology group \(H^n(\mathcal{S}_P;\, \mathcal{F}_J)\). The degree \(n\) encodes the severity of the failure.
Let \(\mathcal{F}_J\) be the judgment sheaf. The obstruction class of a judgment \(J\) is \[ O(J) \;\in\; \bigoplus_{n \ge 0} H^n(\mathcal{S}_P;\, \mathcal{F}_J). \] The degree of \(O(J)\) classifies the discharge status:
The Obstruction Exact Sequence
For a short exact sequence of sheaves \(0 \to \mathcal{A} \to \mathcal{B} \to \mathcal{C} \to 0\) on \(\mathcal{S}_P\), the long exact cohomology sequence is:
\[ 0 \to H^0(\mathcal{A}) \to H^0(\mathcal{B}) \to H^0(\mathcal{C}) \xrightarrow{\,\delta\,} H^1(\mathcal{A}) \to H^1(\mathcal{B}) \to H^1(\mathcal{C}) \xrightarrow{\,\delta\,} H^2(\mathcal{A}) \to \cdots \]The connecting homomorphism \(\delta\) is JuGeo's repair operator: it takes a global section of \(\mathcal{C}\) (a verified sub-judgment) and produces the obstruction in \(H^1(\mathcal{A})\) that remains to be repaired.
Obstruction Persistence and the Cohomology Ring
Obstructions are persistent: they are stored with the judgment and survive incremental recompilation. Moreover, the cup product
\[ \smile \;:\; H^m(\mathcal{S}_P;\, \mathcal{F}) \times H^n(\mathcal{S}_P;\, \mathcal{F}) \;\longrightarrow\; H^{m+n}(\mathcal{S}_P;\, \mathcal{F}) \]gives the set of obstruction classes the structure of a graded ring. This ring can be queried — e.g., to find all judgments whose obstruction is in the same cohomology class (likely sharing a common root cause) — and used to plan repair strategies.
Four Obstruction Operations
| Operation | Formula | Effect |
|---|---|---|
| Query | \(\mathrm{obs}(J)\) | Return the current obstruction class \(O(J) \in H^*\). |
| Transport | \(f^* O(J)\) | Pull back an obstruction along a morphism; useful for propagating known failures to call sites. |
| Repair | \(\mathrm{repair}(J, \pi)\) | Provide new evidence \(\pi\) to reduce \(O(J)\): if \(\pi\) resolves the \(H^1\) cocycle, the obstruction descends to \(H^0 = 0\). |
| Challenge | \(\partial J\) | Issue a challenge: if successful, promotes the obstruction degree; if rebutted, restores the previous class. |
from jugeo.geometry.site import Coordinate, CoordinateKind
from jugeo.geometry.covers import Cover
from jugeo.geometry.descent import GluingData
base = Coordinate(("mypackage",), CoordinateKind.MODULE)
left = Coordinate(("mypackage", "validate"), CoordinateKind.FUNCTION)
right = Coordinate(("mypackage", "emit"), CoordinateKind.FUNCTION)
cover = Cover(
target=base,
patches=(left, right),
overlaps=((left.key, right.key),),
provenance=("docs",),
)
gluing = GluingData.from_cover(
cover,
{
left.key: {"status": "ok", "currency": "USD"},
right.key: {"status": "ok", "currency": "EUR"},
},
)
cocycle = gluing.compute_cocycle()
print(cocycle.dimension)
print(cocycle.summary())
7. Semantic Moves
A semantic move is an atomic proof-search operation that transforms one or more judgments. Moves play the role that tactics play in interactive theorem provers, but they operate on the geometric structure of judgments rather than on proof terms. JuGeo defines 16 primitive moves; users may compose them into strategies.
A semantic move is a partial function \[ m : \mathrm{Judgment}^k \;\rightharpoonup\; \mathrm{Judgment}^l \] together with: (i) a precondition \(\mathrm{pre}(m)\) stating when \(m\) is applicable, (ii) a postcondition} \(\mathrm{post}(m)\) stating what the output judgments satisfy, and (iii) a trust monotonicity guarantee: \(\forall i,\, T(\text{output}_i) \succeq T_{\min}(m)\).
Move Composition and Strategy DSL
Moves compose via a small DSL. The sequential combinator \(m_1 \,;\, m_2\) applies \(m_1\) then \(m_2\) on the output; the parallel combinator \(m_1 \parallel m_2\) applies both to independent sub-judgments simultaneously; and the try combinator \(m_1 \mathbin{||} m_2\) applies \(m_2\) when \(m_1\) fails:
\[ \text{strategy} \;::=\; m \;\mid\; m_1 \,;\, m_2 \;\mid\; m_1 \parallel m_2 \;\mid\; m_1 \mathbin{||} m_2 \;\mid\; \mathrm{repeat}(m) \;\mid\; \mathrm{try}(m) \]from jugeo.evidence.trust import TrustAlgebra, TrustLevel
from jugeo.moves import MoveKind
algebra = TrustAlgebra()
combined = algebra.meet(TrustLevel.SOLVER_DISCHARGED, TrustLevel.HUMAN_ATTESTED)
print(combined)
print([move.name for move in MoveKind][:6])
8. Python Effects as Sheaf Sections
Python's effect system — exceptions, mutable state, asynchronous suspension, generators, context managers — maps precisely onto the geometric language of sheaves. This correspondence is not merely an analogy; it is the formal bridge that lets JuGeo extract judgments automatically from unannotated Python code.
Every Python effect is a sheaf-theoretic operation on the judgment sheaf \(\mathcal{F}_J\) over \(\mathcal{S}_P\). The effect system of the runtime is the transition system of the site; tracking effects equals tracking how sections transform.
| Python Effect | Sheaf-Theoretic Counterpart | Judgment Impact |
|---|---|---|
Exceptions (raise / except) |
Coordinate forks: a raise creates a new branch coordinate
\(\text{Branch}_{\mathrm{exc}}\) disjoint from the normal-exit branch. |
A control-flow cover splits into \(\{U_{\mathrm{normal}},\, U_{\mathrm{exc}}\}\); the postcondition judgment must be separately discharged on each branch. |
Mutable state (=, heap writes) |
Scope sections: each assignment extends the section at the current \(\text{Scope}(f, d)\) coordinate with a new variable binding. | Dataflow-induced assumptions propagate forward through scope morphisms; stale bindings are invalidated by restriction to the updated scope. |
Async / Await (async def, await) |
Suspended morphisms: an await point introduces a
morphism \(\text{Scope}(f, d_{\mathrm{pre}}) \to \text{Scope}(f, d_{\mathrm{post}})\)
that may be traversed zero or more times non-deterministically. |
Temporal covers capture interleaved executions; the sheaf condition guarantees that invariants holding at every yield point glue to a global coroutine invariant. |
Generators (yield) |
Fiber restrictions: each yield is a restriction of the
function-scope section to a fiber} — the state of the generator at that point in
the iteration sequence.
|
A generator body judgment is a family of fiber-level judgments; gluing them produces the loop invariant of the iteration protocol. |
Context managers (with) |
Covering families: __enter__ and __exit__
together form a two-element cover
\(\{U_{\mathrm{open}},\, U_{\mathrm{close}}\}\) of the managed scope. |
Resource invariants are specified on the cover; JuGeo verifies that every exit path
(normal and exceptional) satisfies the cleanup postcondition of __exit__. |
Example: Exception Branches
from jugeo.easy import spec
review = spec(
'''
def sum_positive(items):
total = 0
for x in items:
if x < 0:
raise ValueError(f"negative item: {x}")
total += x
return total
''',
'''
def spec(result, items):
return result >= 0
''',
input_cover=[
{"args": [[1, 2, 3]], "kwargs": {}},
{"args": [[]], "kwargs": {}},
],
entrypoint="sum_positive",
)
print(review)
print(review.satisfied, review.witness_count)
Example: Context Manager as Covering Family
from jugeo.easy import bugs
result = bugs('''
def load_text(path):
fh = open(path, "r")
return fh.read()
''')
print(result)
for bug in result.items:
print(bug.message)
The Effect-Sheaf Correspondence
The correspondence can be stated as a theorem relating Python's operational semantics to the sheaf-theoretic model:
Let \(P\) be a Python program and \(\mathcal{F}_J\) the associated judgment sheaf on \(\mathcal{S}_P\). For every effect \(e\) generated by the Python runtime during execution of \(P\):
\[ e \text{ is safe w.r.t. the effect specification} \;\Longleftrightarrow\; J_e|_{U_{\mathrm{pre}}} \in \mathcal{F}_J(U_{\mathrm{pre}}) \;\text{ and }\; J_e|_{U_{\mathrm{post}}} \in \mathcal{F}_J(U_{\mathrm{post}}), \]where \(U_{\mathrm{pre}}\) and \(U_{\mathrm{post}}\) are the pre- and post-coordinates of \(e\), and safety is preserved by descent: if the local judgments are discharged and satisfy the descent condition, the global effect-safety judgment holds.