Add FORK_STRATEGY.md documenting: - Purpose: HoTT-compatible kernel extensions (Path types without UIP, transport, HITs) for polytropos's meta-theory. - Why kernel-level: library encodings via Quot leak UIP, incompatible with univalence. Mirrors Cubical Agda's precedent. - Sync strategy: track upstream leanprover/lean4, merge (not rebase), preserve HoTT additions on conflict. - Modification strategy: locality principle (new files under hott/ + src/kernel/hott/ + src/Init/HoTT/); LEAN4-HTT: tag for modifications to upstream files; compile-time feature flag (LEAN_HOTT) gates HoTT. - Patch-series organization for phased primitive additions. - Forbidden moves: no UIP at kernel level, no Quot.sound dependency for HoTT reductions, no Classical.choice in HoTT primitives. Add hott/ directory structure: - hott/README.md describing the fork-specific directory's purpose. - hott/design/ for architectural decisions per phase. - hott/tests/ for HoTT-specific test suites. No kernel modifications in this phase. Subsequent phases: Phase 1: Path + Refl + J primitives Phase 2: transport with computational behavior Phase 3: HIT support Phase 4: cubical primitives if needed Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.3 KiB
lean4-htt: Fork Strategy
This is a fork of leanprover/lean4 maintained for HoTT-compatible kernel extensions. The fork exists to add foundational primitives that upstream Lean does not provide: identity Path types without UIP, transport with full computational behavior, higher inductive types (HITs), and (eventually) cubical primitives.
The fork is the meta-theoretic foundation for the polytropos project (a
cubical-transport HoTT engine). Polytropos's σ-calculus and substitution
machinery need HoTT-compatible meta-level reasoning that cannot be built
out of standard Lean inductive types alone without leaking UIP via
Quot.sound + propext.
Why kernel-level, not library-level
Standard Lean library encodings of HoTT (e.g., via Quot) inherit UIP
from the kernel's quotient axiom. UIP is incompatible with univalence:
in a univalent universe, paths between types can be non-trivially
distinct, and UIP collapses this. The fork avoids this by adding Path
types as kernel primitives with their own reduction rules — no Quot
trapdoor, no inherited UIP.
This is the same engineering decision Cubical Agda made when extending Agda with cubical primitives. The work is bounded, the precedent exists, the architectural pattern is known.
Sync strategy with upstream
The fork tracks leanprover/lean4 (upstream remote) and publishes to
maxgit.wg/max/lean4-htt (origin remote).
Sync cadence
Merge from upstream regularly. The cadence is "frequently enough that each merge is mechanical" rather than a fixed schedule. Typical triggers:
- New upstream release
- Significant upstream features (e.g., LLVM backend updates, compiler improvements) that we want to inherit
- After any local modification, before extending further
Merge over rebase
The fork uses merges (not rebases) when pulling upstream. Rationale:
- Preserves the divergence history visibly in git log
- Avoids force-pushing the fork's master branch
- Makes each upstream sync a single commit (the merge commit) that can be examined or reverted
Conflict resolution discipline
When upstream and the fork modify the same file:
- Resolve in favor of preserving the fork's HoTT additions
- Verify the merged result still passes both upstream's tests and the fork's HoTT-specific tests
- Document non-trivial conflicts in the merge commit's body
If upstream restructures something the fork depends on (e.g., changing
the Expr representation, refactoring whnf), the fork's patches need
re-application. Keep modifications localized so re-application is
mechanical.
Modification strategy
Locality principle
Add HoTT primitives in NEW files where possible:
src/kernel/hott/path.cpp,src/kernel/hott/transp.cpp, etc.src/Init/HoTT/for Lean-side exposure of the new primitiveshott/directory at the repo root for fork-specific design docs, rationale, and tests
Only modify existing upstream files where the kernel architecture requires it:
src/kernel/expr.h(or equivalent): add newExpr::Kindvariantssrc/kernel/whnf.cpp(or equivalent): add a single hook that dispatches to the HoTT reducersrc/kernel/type_checker.cpp(or equivalent): add a single hook for HoTT inference rules
Every modification to an upstream file is documented with a comment
naming what it does and why. The grep-friendly tag is LEAN4-HTT:.
Feature flag (compile-time gating)
HoTT primitives are gated behind a compile-time flag (likely a CMake
option LEAN_HOTT=ON). When OFF, the fork builds as vanilla Lean.
When ON, the HoTT extensions activate.
This reduces upstream-merge friction: most upstream changes don't touch HoTT code paths, so they merge cleanly into the fork. It also gives a testable "is the fork still upstream-equivalent in vanilla mode?" property.
Patch-series organization
HoTT additions are organized as a series of focused commits, each adding one cohesive feature:
- Commit: add
Pathtype former - Commit: add
Reflconstructor - Commit: add
Jeliminator + reduction - Commit: add
transport+ reduction - Commit: add HIT support
- etc.
Each commit is self-contained where possible. If upstream restructures something that breaks a commit's assumptions, that commit can be identified and re-applied without disturbing the others.
Directory structure
lean4-htt/
├── FORK_STRATEGY.md # this file
├── hott/ # fork-specific design + tests
│ ├── README.md # what's in this directory
│ ├── design/ # architectural decisions
│ └── tests/ # HoTT-specific test suites
├── src/ # upstream Lean source (modified per locality principle)
│ ├── kernel/
│ │ ├── hott/ # new directory for HoTT kernel primitives
│ │ └── ... # upstream files; LEAN4-HTT: tags mark modifications
│ ├── Init/
│ │ ├── HoTT/ # new directory for Lean-side HoTT API
│ │ └── ... # upstream files
│ └── ... # rest of upstream src
├── tests/ # upstream tests (run unchanged)
└── ... # rest of upstream files
CI and verification
Two test suites:
- Upstream's full test suite, run in
LEAN_HOTT=OFFmode. Must pass with no regression. - The fork's HoTT-specific test suite under
hott/tests/, run inLEAN_HOTT=ONmode. Verifies the new primitives behave correctly.
CI runs both on every commit to the fork's master.
Forbidden moves
The fork's HoTT extensions must not:
- Introduce UIP at the kernel level (defeats the purpose of forking)
- Depend on
Quot.soundfor HoTT primitive reductions - Use
Classical.choicein HoTT primitive implementations - Add ad-hoc axioms beyond the minimum needed for soundness
If a HoTT primitive cannot be implemented constructively (no axioms, no UIP-leaky principles), it doesn't go in the fork. This is the same discipline polytropos enforces at the engine's object level.
Maintenance
The fork's maintainer:
- Runs upstream sync per the cadence above
- Resolves conflicts preserving HoTT additions
- Updates
FORK_STRATEGY.mdwhen the strategy evolves - Documents non-mechanical decisions in
hott/design/
The fork is at maxgit.wg/max/lean4-htt.
Phases
This is Phase 0: fork infrastructure (this file, directory structure, remotes, sync workflow). No kernel modifications yet.
Subsequent phases add HoTT primitives:
- Phase 1: minimal
Path+Refl+J(the foundational core) - Phase 2:
transportwith full computational behavior - Phase 3: HIT support
- Phase 4: cubical primitives (interval, faces, Glue) if needed for polytropos's full spec
Each phase is gated on the previous landing and passing both test suites.
Related projects
- polytropos — the cubical-transport HoTT engine that depends on this fork.
- Cubical Agda — the precedent for adding cubical primitives to a host proof assistant.
- topolei — the prior project that used Rust FFI for the computational kernel; informs the architectural pattern for foundational extensions.