agda-algebras — GitHub Project Roadmap¶
Project Title: agda-algebras 3.0 — Infrastructure, Consolidation, Classical Structures, Applications
Repository: ualib/agda-algebras
Date: 2026-04-19
Summary¶
Modernization of agda-algebras in 10 milestones: tooling upgrade/infra (M1), consolidate Base/Setoid (M2), classical structures (M3), style/naming uniformity (M4), Cubical Agda (M5), FLRP (M6), complexity/CSP module (M7), training corpus/LLM (M8), novel-research apps of Continuous relation API (M9), and post-3.0 polish — rendering pipeline, organization transfer, and Nix packaging (M10).
Description¶
A structured plan to modernize the agda-algebras library. The work is organized into ten milestones: tooling upgrade and infrastructure (M1), consolidation of the Base/Setoid fork (M2), introduction of the long-missing classical structures layer (M3), style and naming uniformity (M4), a Cubical Agda proof-of-concept as the canonical long-term target (M5), prerequisites for work on the Finite Lattice Representation Problem (M6), an extension of the existing algebraic complexity / CSP module for finite templates (M7), publication of a training corpus for language-model work (M8), novel-research applications of the Continuous relation API (M9), and a post-3.0 polish layer — rendering-pipeline modernization, transfer to the official agda GitHub organization, and first-class distribution through nixpkgs (M10). After M1 lands, the remaining milestones run largely in parallel; M10 in particular requires only M1, M2, and M4 to be complete and runs alongside M5–M9 rather than after them.
Note on version numbering¶
agda-algebras was released as v2.0.1 in December 2021 (Zenodo DOI 10.5281/zenodo.5765793) as an archival artifact for the TYPES 2021 submission. The current reconstruction is a major version bump past that release and is planned as v3.0. The planned Cubical-canonical successor, in which src/Cubical/ becomes the default development tree, is planned as v4.0.
Labels¶
milestone-1-infra(0075ca) — Milestone 1: Infrastructure health.milestone-2-consolidation(0075ca) — Milestone 2: Consolidation.milestone-3-classical(0075ca) — Milestone 3: Classical structures layer.milestone-4-style(0075ca) — Milestone 4: Style and naming uniformity.milestone-5-cubical(5319e7) — Milestone 5: Cubical track.milestone-6-flrp(5319e7) — Milestone 6: FLRP prerequisites.milestone-7-csp(5319e7) — Milestone 7: Algebraic complexity / CSP.milestone-8-llm(5319e7) — Milestone 8: LLM readiness.milestone-9-apps(5319e7) — Milestone 9: Applications of continuous relations.milestone-10-polish(5319e7) — Milestone 10: Post-3.0 polish (rendering, organization transfer, packaging).stdlib-bridge(fbca04) — Bridges to the Agda standard library.breaking-change(d93f0b) — Breaking change to the public API.good first issue(7057ff) — Good for newcomers.help-wanted(0e8a16) — Community help wanted.design-discussion(c5def5) — Needs design discussion before implementation.documentation(0e8a16) — Documentation changes.governance(8aea29) — Administration and governanceagda-community(945ca0) — Topics relevant to the Agda community.
Milestones¶
Milestone 1 — Infrastructure health (BLOCKING)¶
Description. Modernize the library's tooling, establish baseline project hygiene, and unblock every subsequent milestone. The library is currently pinned to Agda 2.6.2 / stdlib 1.7; it must move to Agda 2.8.0 / stdlib v2.3 with --cubical-compatible replacing --without-K. Standard community-health files (CONTRIBUTING, CHANGELOG, CODE_OF_CONDUCT, STYLE) must land. GitHub Actions CI must stand up. README and installation docs must be rewritten for the 3.0 line.
Exit criterion. make check passes under GitHub Actions CI against Agda 2.8.0 / stdlib v2.3; CONTRIBUTING.md, docs/STYLE_GUIDE.md, ROADMAP.md, CHANGELOG.md are merged; README documents the new install path.
Milestone 2 — Consolidation¶
Description. Resolve the parallel Base/Setoid fork by freezing Base/ and moving it to Legacy/Base/. Setoid/ is the canonical development tree for 3.0. Within Legacy, consolidate redundant Base.Structures implementations and remove abandoned experimental modules. Designate a single canonical proof of Birkhoff's HSP theorem while preserving the pedagogical demonstration variants.
Exit criterion. src/Base/ is in src/Legacy/Base/ with a deprecation note; Setoid.Varieties.HSP.Birkhoff is designated canonical; ADR-001 (Setoid as canonical) is merged; no duplicate implementations of the same concept remain in Setoid/ or Legacy/Base/.
Milestone 3 — Classical structures layer¶
Description. Introduce the long-missing tower of classical algebraic structures as Σ-typed specific theories over the universal-algebra framework, with record-typed bundle views matching the stdlib Algebra.Bundles idiom. Each structure ships as a Signatures / Theories / Structures / Bundles / Small quintuple. Designed so that the underlying equivalence used in the Setoid-based 3.0 line can be mechanically replaced by a Cubical path type when the 4.0 Cubical track becomes canonical.
Phase 1: Magma, Semigroup, CommutativeSemigroup, Monoid, CommutativeMonoid, Group, AbelianGroup, Semilattice, Lattice.
Phase 2: Ring, CommutativeRing, Field, Module, DistributiveLattice, BooleanAlgebra.
Exit criterion. Phase 1 classical structures are implemented, documented, bridged to stdlib, and exercised by at least one worked example each (e.g. (ℕ, +, 0) as a CommutativeMonoid; (ℤ, +, -, 0) as an AbelianGroup).
Milestone 4 — Style and naming uniformity sweep¶
Description. Apply docs/STYLE_GUIDE.md consistently across Setoid/ and Classical/. Audit naming (one preferred name per concept; synonyms deprecated); audit notation (one canonical symbol table); audit module structure (one concept per module where feasible); ensure every user-facing definition has a prose comment block.
Exit criterion. No undocumented public definitions remain in Setoid/ or Classical/; no synonym pairs (e.g. is-homomorphism + IsHom) exist in the public API; the canonical symbol table in docs/STYLE_GUIDE.md matches the notation actually used in the library.
Milestone 5 — Cubical track (canonical long-term target)¶
Description. Prepare the path for Cubical/ to become the canonical development tree in version 3.0. Port Algebra to cubical Agda, prove the structure identity principle (SIP), prove equivalence of ≅ with path equality, and demonstrate end-to-end workflow by porting at least one classical structure (Monoid is the natural choice).
Exit criterion. Cubical/Algebras/Basic.agda compiles; SIP is proven for the cubical Algebra record; Monoid has a working cubical port that is essentially a mechanical substitution from its Setoid analog; ADR-003 (Cubical as canonical target) is merged.
Milestone 6 — Toward the Finite Lattice Representation Problem¶
Description. Build the specialized universal-algebraic infrastructure needed to tackle the Finite Lattice Representation Problem: "Does every finite lattice occur as the congruence lattice of a finite algebra?" Near-term prerequisites include Con 𝑨 and Sub 𝑨 as complete lattices, subdirect products, subdirectly irreducible algebras, and basic Maltsev conditions relevant to lattice representations. Medium-term. Jónsson's theorem, Day's theorem. Long-term (out of scope for 3.0): tame congruence theory, commutator theory, explicit representations of small lattices.
Exit criterion. Con 𝑨 is a complete lattice; subdirect products and subdirectly irreducible algebras are defined with basic properties proven; at least one Maltsev condition (congruence permutability via the Maltsev term characterization) is proven.
Milestone 7 — Algebraic complexity / CSP extensions (finite templates)¶
Description. Extend the existing Base.Complexity / Exercises.Complexity.FiniteCSP work into a proper algebraic-complexity development of finite-template constraint satisfaction. This is a separate research program from Milestone 6 (the FLRP is about lattice representation theory; finite CSP is about the complexity of constraint satisfaction with a fixed finite template over the algebraic approach of Bulatov, Zhuk, Barto, and others). Candidate content includes polymorphism clones, the Jeavons Galois connection, Post's lattice, and a statement of the Bulatov–Zhuk algebraic dichotomy. The infinite-template / ω-categorical extension is covered separately under Milestone 9.
Exit criterion. At least one substantial algebraic-CSP theorem is formalized (e.g. the Jeavons Galois connection for a fixed finite domain); polymorphism clones are available as a first-class type.
Milestone 8 — LLM readiness and corpus artifacts¶
Description. Make the library maximally useful as a training and retrieval corpus for language models. Extract (theorem statement, proof term) pairs with metadata; publish as a Hugging Face dataset; explore agda-native-air integration; publish a short paper or blog post describing the corpus and its intended uses.
Exit criterion. Initial corpus artifact is published with at least 500 (theorem, proof) pairs; a CI job regenerates the corpus on each release; a public-facing write-up describing the dataset is available.
Milestone 9 — Applications of continuous relations¶
Description. Explore substantive mathematical applications of the Continuous relation API — the generalization of classical relations to arbitrary arity types, developed in Base.Relations.Continuous and carried forward into Setoid/. Three directions are in scope, each intrinsically interesting and independent of the FLRP and finite-CSP programs. M9-1 formalizes Scott-continuous relations on directed-complete partial orders (DCPOs), connecting to domain theory and Escardó's work on searchable sets in the constructive-mathematics tradition. M9-2 formalizes infinitary CSP over ω-categorical templates in the Bodirsky–Pinsker program, where relations of countably infinite arity arise naturally. M9-3 is exploratory rather than deliverable-oriented: a reading-and-writing investigation into whether coalgebraic bisimulation has an under-exploited angle at the intersection with universal algebra in the Birkhoff sense.
Exit criterion. At least one of M9-1 or M9-2 produces a formalized non-trivial example accompanied by a short public write-up (blog post, arXiv note, or similar); M9-3 produces a design-discussion document summarizing what was learned from the reading, with a concrete verdict ("pursue" or "saturated") regardless of whether formalization work follows.
Milestone 10 — Post-3.0 polish (community packaging and presentation)¶
Description. Independent polish items that finalize agda-algebras' presentation as a community-grade library, separated out from the body of the 3.0 modernization work because each is most valuable applied to a library already in production-grade shape, but none of them depends on M5–M9, and M10-1 in particular can begin as soon as M1, M2, and M4 are complete and run in parallel with the rest.
- M10-1: modernize the rendering pipeline by replacing the Jekyll-based
admin/generate-htmlmachinery with a MkDocs site consumed directly from.lagda.mdsources. - M10-2: transfer the repository to the official
agdaGitHub organization to align governance with the rest of the Agda ecosystem. - M10-3: promote the library to a first-class entry under
nixpkgs.agdaPackagesso downstream Nix users can depend on it without vendoring a flake input.
M10-2 and M10-3 are governance/packaging tasks with no hard structural prerequisites inside the milestone tree; they sit in M10 for thematic grouping (post-3.0 community polish) rather than for dependency reasons. Pursuing them prematurely, before the library itself is in 3.0-ready shape, undermines the goals these tasks aim to achieve, which is why they're tagged with this milestone rather than M1 or M2.
Exit criterion. MkDocs site live at https://ualib.org with make site building cleanly under nix develop; the repository is hosted at agda/agda-algebras with HTTP redirects from the old ualib/ URL working transparently; nix-shell -p 'agdaPackages.agda-algebras' produces a working environment in which agda --library agda-algebras resolves correctly.
Milestone Dependencies¶
graph TD
M1["M1 — Infrastructure"]
M2["M2 — Consolidation"]
M3["M3 — Classical structures"]
M4["M4 — Style sweep"]
M5["M5 — Cubical"]
M6["M6 — FLRP prerequisites"]
M7["M7 — CSP (finite templates)"]
M8["M8 — LLM corpus"]
M9["M9 — Continuous-relation apps"]
M10["M10 — Post-3.0 polish"]
M1 --> M2
M1 --> M4
M1 --> M5
M1 --> M10
M2 --> M3
M2 --> M7
M2 --> M9
M2 --> M10
M3 --> M5
M3 --> M6
M3 --> M7
M3 --> M9
M4 --> M8
M4 --> M10
M7 -.-> M9
Issues¶
Below, each issue is tagged with its milestone (M1, M2, etc.), suggested labels, and a full issue body ready for GitHub. Cross-milestone dependencies are noted in the body; see the Mermaid graph at the end of this file for a visual summary.
---¶
Milestone 1 — Infrastructure health¶
Issue M1-1: Upgrade to Agda 2.8.0 and stdlib v2.3; replace --without-K with --cubical-compatible (#250, closed)¶
Labels: milestone-1-infra, breaking-change
Description¶
The library is currently pinned to Agda 2.6.2 / stdlib 1.7. The Agda ecosystem has moved on: the current stable is Agda 2.8.0 (July 2025) and stdlib v2.3. --without-K has been superseded by --cubical-compatible since Agda 2.6.3. This issue tracks the full upgrade. Blocks essentially every other issue in this project.
Tasks¶
- Update
agda-algebras.agda-libtodepend: standard-library-2.3and document the minimum Agda version as 2.8.0. - Replace every
{-# OPTIONS --without-K --exact-split --safe #-}with{-# OPTIONS --cubical-compatible --exact-split --safe #-}. - Fix any regressions from the flag change.
- Update import paths for anything that moved between stdlib 1.7 and 2.3 (expected hotspots:
Function.Bundles,Relation.Binary.*renamings,Data.*reorganizations). - Update CI config to test against Agda 2.8.0 / stdlib 2.3.
- Update
README.mdandINSTALL.mdto reflect the new requirements. - Update the Nix flake.
Acceptance criteria¶
- Library type-checks under Agda 2.8.0 / stdlib v2.3.
-
make checksucceeds locally. - No file still declares
--without-K. - Once 2.0 is stable, consider adding a CI job against Agda 2.9/dev to catch forward-compatibility issues early.
Issue M1-2: Add GitHub Actions CI to type-check the library (#251, closed)¶
Labels: milestone-1-infra, nix, ci
Description¶
The library has no CI. Contributors can break type-checking without maintainers noticing. Add a GitHub Actions workflow that type-checks the library on each push and pull request. Reference workflows: agda-categories and the stdlib itself both have well-maintained CI that can be adapted.
Tasks¶
- Add
.github/workflows/ci.yml. - Install Agda at the pinned version (Agda 2.8.0; see M1-1).
- Install stdlib v2.3.
- Run
make check(or equivalent) on every push tomainand on PRs. - Cache the Agda binary and
.agdaifiles between runs. - Display a CI badge in the README.
Acceptance criteria¶
- CI runs green on
main. - CI triggers on every pull request.
- Average job time < 10 min after caching.
- README shows a green CI badge.
Issue M1-3: Add CONTRIBUTING.md, CHANGELOG.md, CODE_OF_CONDUCT.md (#252, closed)¶
Labels: documentation, milestone-1-infra
Description¶
Standard community-health files are missing. Drafts of CONTRIBUTING.md and docs/STYLE_GUIDE.md may exist from the 3.0 planning cycle and could be merged after review.
Tasks¶
- Add
CONTRIBUTING.md(draft from planning cycle). - Add
CHANGELOG.mdseeded with the 3.0 milestone entry. - Add
CODE_OF_CONDUCT.md(Contributor Covenant 2.1). - Add
.github/ISSUE_TEMPLATE/with bug-report, feature-request, and design-discussion templates. - Add
.github/PULL_REQUEST_TEMPLATE.md.
Acceptance criteria¶
- All four files exist at the repo root (or in
.github/). - GitHub recognizes the community-health files (green checkmarks on the "Insights → Community standards" page).
Issue M1-4: Adopt docs/STYLE_GUIDE.md as the project style guide (#253, closed)¶
Labels: documentation, milestone-1-infra
Description¶
Create docs/STYLE_GUIDE.md documenting file format, module structure, naming conventions, notation, universe-polymorphism practices, record vs Σ guidance, proof style, and library-as-training-corpus considerations. A draft from the planning cycle is ready for review. Applying the style guide across Setoid/ and Classical/ is tracked in M4-1.
Tasks¶
- Merge
docs/STYLE_GUIDE.md(draft from planning cycle). - Link
docs/STYLE_GUIDE.mdfromREADME.mdandCONTRIBUTING.md.
Acceptance criteria¶
-
docs/STYLE_GUIDE.mdis merged. - Links from README and CONTRIBUTING work.
Issue M1-5: Rewrite README and Preface for the 3.0 release (#254, closed)¶
Labels: documentation, milestone-1-infra
Description¶
The current README.md and docs/lagda/Overture/Preface.lagda are 1.x-era: wrong Agda versions, obsolete installation paths, pre-consolidation library structure. They need a rewrite aligned with the 3.0 release. Depends on M1-1 through M1-4 and M2-1.
Tasks¶
- Pin Agda 2.8.0 / stdlib 2.3 in install instructions.
- Describe the Setoid-as-canonical structure and point to
Classical/. - Link
CONTRIBUTING.md,GITHUB_PROJECT.md,docs/STYLE_GUIDE.md. - Concrete quickstart for new users (5-command install →
make check). - Add CI badge (from M1-2) and documentation site link.
- Consider whether to merge
docs/lagda/Overture/Preface.lagdaandsrc/Overture/Preface.agdainto new Markdown-based literate Agda file calledsrc/Overture/Preface.lagda.mdat this stage or put this off to a later milestone/issue/release.
Acceptance criteria¶
- A reviewer can follow the README on a clean machine to a working
make checkwithout asking questions. - All links resolve.
- ~~No references to Agda 2.6.x or stdlib 1.x remain.~~ Current installation/setup guidance no longer instructs users to use Agda 2.6.x or stdlib 1.x; any remaining references are clearly historical or archival rather than normative.
- A decision is made to either merge Preface{.lagda,.agda} files into one Markdown-based literate Agda file, or make a new issue for applying the
.lagda+.agda=>.lagda.mdtransformation across entire code base (e.g., using a script like the one we developed at IO for converting LaTeX-based to Markdown-based literate Agda).
Issue M1-6: Establish docs/adr/ for Architecture Decision Records (#255, closed)¶
Labels: documentation, milestone-1-infra
Description¶
As the library evolves, design decisions (Setoid vs Base canonicality, record vs Σ for classical structures, Cubical track planning) should be recorded so future contributors understand the rationale. Use Michael Nygard's lightweight ADR format (one page per decision).
Tasks¶
- Create
docs/adr/directory. - Add
docs/adr/README.mdexplaining the ADR format. - Add
docs/adr/000-template.md. - Seed with decisions ratified in 2.0:
001-setoid-as-canonical.md(from M2-1);002-classical-layer-design.md(from M3-1);003-cubical-canonical-target.md(from M5-1).
Acceptance criteria¶
-
docs/adr/exists with README and template. - All three seeded ADRs are drafted (full content can land with the associated implementation issues).
Issue M1-8: Consolidate literate and bare-Agda sources into .lagda.md (#280, closed)¶
Labels: documentation, milestone-1-infra, breaking-change
Problem¶
The repository currently maintains literate Agda sources in two formats and two locations.
src/X/Y/Z.agda— minimal module skeletons that the type checker sees (typically just the OPTIONS pragma andmodule ... where).docs/lagda/X/Y/Z.lagda— the corresponding LaTeX-literate Agda content used bymake htmlto generate the rendered documentation at https://ualib.org.
This is a maintenance hazard and directly undermines the library-as-corpus pillar, since prose and proof in two files must be held in sync by hand.
The fix is to migrate to Markdown-literate Agda (.lagda.md), consolidating each module into a single src/X/Y/Z.lagda.md file that is both type-checked by make check and rendered by make html. An existing LaTeX-literate-to-Markdown-literate conversion script developed by @williamdemeo at IOHK is available and could be useful here.
Open design questions¶
A short design discussion is needed before code is written; the resolutions should be recorded in docs/adr/004-lagda-md-canonical.md.
- What happens to
docs/lagda/after migration? Recommend: delete; everything moves tosrc/. Implication: external bookmarks pointing to specificdocs/lagda/X.lagdapaths will break — audit and document the breakage. - Are there files we should keep in LaTeX-literate form? Paper companions under
docs/papers/may be co-built with a LaTeX paper PDF and arguably should stay. Itemize and decide individually. - How does Jekyll site generation change? The current
admin/generate-htmlpipeline type-checks.lagdafiles and post-processes the resulting.texand.htmlfor Jekyll consumption. The replacement runsagda --htmlon.lagda.mdfiles (which produces Markdown with fenced code blocks, suitable for direct Jekyll consumption) and may obviateadmin/generate-texentirely.
Proposal¶
Pre-work and design¶
- Extract and generalize the IOHK conversion script; done (see agda-lagda-migrator).
- Confirm agda-lagda-migrator produces well-formed
.lagda.mdon a representative sample (suggested:Overture/Preface,Setoid/Algebras/Basic,Demos/HSP). - Audit current state: count of
.lagdafiles, count of.agdaskeletons paired with.lagdacontent, count of.agdafiles with substantive content. - Confirm Agda 2.8.0's
.lagda.mdsupport is fully functional under--cubical-compatible --exact-split --safe. - Inventory hard-coded paths to specific
.lagdafiles across the repository (commit messages, BibTeX notes, paper PDFs, README links, internal cross-references, Jekyll templates). - Write ADR
docs/adr/004-lagda-md-canonical.mdresolving the open design questions above.
Build-system changes¶
- Update the Nix flake's
shellHookand the.agda-libinclude-path rules as needed (they should Just Work;.lagda.mdis treated as Agda source by the compiler). - Update
Makefile's Everything.agda generation pattern to pick up*.lagda.mdfiles alongside*.agda(currentlyfind $(SRCDIR) -name '*.agda'matches neither.lagdanor.lagda.md; change tofind src -name '*.lagda.md' -o -name '*.agda'; Agda will handle either, though going forward everything should be.lagda.md). - ~~Consider adding a
make corpustarget that extracts (prose, code-block) pairs into JSONL — first piece of M8 (LLM readiness) landing early.~~ (deferred) - ~~Update
admin/generate-htmlto operate on.lagda.mdfiles; remove or deprecateadmin/generate-texif no longer needed.~~ (deferred) - ~~Update Jekyll configuration to consume the Markdown output of
agda --htmldirectly.~~ (deferred) - Update CI workflow if the new pipeline introduces new dependencies.
File migration¶
- Run the conversion script across
docs/lagda/(excluding any items the ADR earmarks to remain LaTeX-literate). - Move output to the matching
src/path with.lagda.mdextension. - Delete the corresponding
src/X/Y/Z.agdaskeleton files. - ~~Update internal cross-references — link definitions,
[Module.Name][]-style references, BibTeXSource codenotes in module headers.~~ (deferred) - ~~Update
_includes/UALib.Links.md(or equivalent) to reflect new paths.~~ (deferred)
Documentation¶
- Update
docs/STYLE_GUIDE.mdto specify.lagda.mdas the canonical literate-Agda format and document the migration outcome. - Update
CONTRIBUTING.mdexamples that reference.lagdafiles. - Update
README.md's BibTeX notes if any reference.lagdapaths (specifically theDeMeo:2021entry'sSource codeURL). - Add a
CHANGELOG.mdentry under [Unreleased] flagging the file-format change as breaking for external links.
Verification¶
-
make checkpasses after migration. - ~~
make htmlproduces equivalent or improved HTML output; spot-check at least 10 rendered pages against a pre-migration archive.~~ (deferred) - ~~All internal cross-references resolve in the rendered HTML.~~ (deferred)
- Round-trip sanity: a representative sample of converted Agda code blocks type-check identically to their pre-migration
.lagdaoriginals.
Acceptance criteria¶
- No
.lagdafiles remain undersrc/ordocs/lagda/outside of any items the ADR explicitly preserves. - No
src/X/Y/Z.agdaskeleton files remain (those that previously paired with adocs/lagda/X/Y/Z.lagdacontent file). -
make check~~andmake html~~ succeeds under the new pipeline. - ~~Rendered HTML output at https://ualib.org is equivalent or improved.~~ (deferred)
-
docs/STYLE_GUIDE.mdspecifies.lagda.mdas canonical. - ADR
docs/adr/004-lagda-md-canonical.mdis merged.
Non-goals¶
- Changing the mathematical content of any module.
- Reorganizing the module hierarchy.
- Re-litigating the choice of literate Agda as the default presentation format.
Why now¶
Several converging considerations make this worth doing in the 3.0 cycle rather than deferring to 4.0.
- Single source of truth. The dual-file split is a structural source of drift between formal content and prose. Consolidation eliminates the drift class entirely.
- Tooling alignment. Markdown is the universal lingua franca; GitHub renders
.lagda.mdnatively, VSCode previews them, and the modern Agda ecosystem (1Lab being the most visible example) has standardized on the format. - Corpus extraction (M8-1). The training-corpus extractor walks the library to emit
(theorem, prose, proof)records. A uniform format with prose and code in one file is materially easier to extract from than a dual-file split where pairing depends on path correspondence. - Onboarding. New contributors find Markdown easier to author than LaTeX-literate Agda; the friction reduction is real.
- Efficiency. Doing this now saves conversion of new Agda modules later.
Relation to other milestones¶
- Sequenced before: M4-2 (docstring pass) — operates on the new file format directly.
- Benefits: M8-1 (LLM corpus) — uniform format simplifies extraction.
- Independent of: M3, M5, M6, M7, M9.
References¶
- 1Lab — large-scale Agda library written in
.lagda.md. - Agda's literate-programming documentation — language reference for
.lagda.mdand other literate formats.
Issue M1-9: Simplify Nix agda wrapper: drop defensive flags and rely on auto-discovery (#285)¶
Labels: milestone-1-infra, design-discussion, nix
Context¶
The current flake.nix generates a wrapper script at $AGDA_DIR/bin/agda that invokes the Nix-provided Agda with four defensive flags:
exec "$NIX_AGDA" \
--no-default-libraries \
--library-file "$AGDA_DIR/libraries" \
--library standard-library \
--library agda-algebras \
"$@"
Each flag was added to address a specific concern at the time it was introduced:
--no-default-librariessuppresses any entries in the user's~/.config/agda/defaultsthat might otherwise leak in (e.g. a globally-registered stdlib 2.2).--library-fileregisters our project-local stdlib + agda-algebras entries.--library standard-libraryensures stdlib is on the include path.--library agda-algebrasensures our library'ssrc/is on the include path (added in #251 after CI revealed that--no-default-librariessuppresses auto-discovery walk-up).
The defensive posture solves real problems, but it also suppresses Agda's normal library-resolution machinery — which exists for good reasons and is what most Agda users rely on.
Hypothesis¶
With the project-local AGDA_DIR already shadowing the user's ~/.config/agda/, the need for defensive flags is largely obviated. Specifically:
- The user's
~/.config/agda/defaultscannot leak in becauseAGDA_DIRpoints to./agda/(a gitignored project-local directory), not~/.config/agda/. The project-localdefaultsis what Agda reads, and we control its contents. - The walk-up-from-file auto-discovery can find the repo-root
agda-algebras.agda-libon its own if we let it.
Proposal¶
Investigate whether the wrapper can be simplified to just:
exec "$NIX_AGDA" \
--library-file "$AGDA_DIR/libraries" \
"$@"
Combined with a project-local $AGDA_DIR/defaults that lists standard-library. This would:
- Restore standard Agda library-resolution behavior (filename walk-up, include-root inference, etc.).
- Make the wrapper match what a developer would expect from having read the Agda docs.
- Reduce the surface area for future bugs of the kind #251 revealed.
Tasks¶
- Write a minimal test case: a file that imports from stdlib and from agda-algebras, check it with only
--library-fileset. Confirm that auto-discovery works as expected. - Verify that no
~/.config/agda/leakage occurs with the simplified wrapper on a developer machine with a globally-registered stdlib of a different version than the pinned one. - If the simpler wrapper works, update
flake.nixto emit it. - Verify the simplification doesn't break Emacs
agda-modeinteractive use (the mode invokesagdaviaagda --emacs-mode, inheriting our wrapper). - Verify
make checkstill passes in CI. - Document the resolution behavior in a
docs/adr/entry (see M1-6).
Non-goals¶
- Breaking CI to prove a point. If any step above reveals a real need for the defensive flags, document it and keep them.
- Reintroducing the flags one at a time incrementally. The point of this issue is to test the "remove all defensive flags" hypothesis; partial regressions aren't informative.
Acceptance criteria¶
- Decision is recorded: either the wrapper is simplified and the simpler version passes
make checklocally and in CI, or an ADR documents why each defensive flag is load-bearing.
Relation to other milestones¶
- Depends on: #251 (M1-2), which establishes the CI baseline this issue would test against.
- Independent of everything else.
Issue M1-10: Script to generate GITHUB_PROJECT.md from GitHub API (#289, closed)¶
Labels: documentation, milestone-1-infra
Problem¶
docs/GITHUB_PROJECT.md is the single-file master plan of the 3.0 upgrade: milestone prose, exit criteria, dependency graphs, and the full set of issue bodies. It was authored by hand during the initial project-planning cycle and then used as input to scripts/gh_project_populate.py to materialize the GitHub milestones, labels, and issues.
After the initial population, GitHub became the authoritative source for issue state — we edit issues on the web, close them as they complete, file new ones. But the markdown file has no mechanism to follow along. Issues added since the initial cycle are not reflected, and this drift will compound as the project progresses.
The file is too useful to abandon — external readers link to it, gh_project_populate.py consumes it, and a single-file view of the entire plan is the most efficient way to share the project state with collaborators (human and AI). The problem is purely that it isn't regenerated.
Proposal¶
Add scripts/gh_project_render.py, a generator that produces docs/GITHUB_PROJECT.md from two inputs:
- GitHub API — issue bodies, milestone assignments (inferred from
milestone-N-*labels), issue state (open/closed); queried via theghCLI in the same style asgh_project_populate.py. - ~~
docs/project_meta.yml— authored-by-hand narrative content that has no home on GitHub: ordered milestone list with description / exit criterion / mermaid dependency graph per milestone; label palette with hex colors and descriptions; file-level preamble and epilogue.~~ Alternative design ratified: all content in one file with markdown comment markers delimiting what should be regenerated.
The generator is sort of inverse to gh_project_populate.py: the latter pushes markdown to GitHub, the former pulls GitHub state back into markdown. Shared data classes (Milestone, Label, Issue) and the GitHubClient wrapper are factored into a small scripts/_gh_project_lib.py module used by both scripts.
Design decisions to ratify¶
- Issue membership is label-inferred, not listed in a separate outline file. The
milestone-N-*labels already used bygh_project_populate.pydetermine which milestone an issue belongs to; within-milestone ordering comes from the[MN-k]prefix in the issue title. Rationale: adding a new issue requires one human action (label it) instead of two (label it + edit an outline). - Dependency graphs are authored by hand as per-milestone mermaid strings. Machine-generation would require a "Depends on #N" convention nobody has committed to and a parser that doesn't exist; manual mermaid is typically less than ten lines per milestone and changes rarely.
GITHUB_PROJECT.mdremains committed, with a generated-file banner at the top, because external links, issue templates, and the library's documentation page all point at it, and because a textual diff on project-structure changes is a useful PR review aid.- Maintenance is initially manual via
make project-plan; a CI staleness check is a follow-up once CI lands in M1-2.
Tasks¶
- Factor shared data classes and the
GitHubClientwrapper out ofgh_project_populate.pyintoscripts/_gh_project_lib.py. - Add
scripts/gh_project_render.pythat queries the GitHub API and emitsdocs/GITHUB_PROJECT.md. - Add a
project-plantarget to theMakefile. - Add a top-of-file banner to
docs/GITHUB_PROJECT.mdnoting that it is generated. - Regenerate
docs/GITHUB_PROJECT.mdand commit the (now byte-reproducible) version. - Update
scripts/README.mdwith usage for the new generator.
Follow-up (not part of this issue)¶
- Once CI exists (M1-2), add a job that re-runs
gh_project_render.pyin a scratch directory, diffs against the committed file, and fails the PR if they differ. Prevents drift at zero ongoing cost.
Acceptance criteria¶
- Running
make project-planon a clean checkout with a validghauth token produces adocs/GITHUB_PROJECT.mdthat matches the committed file byte-for-byte. - All currently-open issues are listed in their correct milestone sections.
- The mermaid dependency graphs render identically to the current hand-authored versions.
-
scripts/README.mddocuments the new workflow.
Issue M1-11: Add Claude Code agent config for Agda type-checking (#349, closed)¶
Labels: milestone-1-infra, nix
Description¶
Add a .claude/ configuration directory so Claude Code on the web can provision the pinned Agda toolchain and type-check the library exactly as CI does (nix develop --command make check). The web container is ephemeral and ships with neither Nix nor Agda, so a SessionStart hook re-provisions the toolchain at the start of every session.
This adds two files:
.claude/settings.json— registers theSessionStarthook..claude/hooks/session-start.sh— an idempotent, web-only hook that installs single-user Nix, enables flakes, and pre-warms the dev shell so Agda 2.8.0 + standard-library 2.3 (pinned byflake.lock) are realized from the binary cache before the agent runs.
Toolchain pinning stays entirely in flake.nix / flake.lock; the hook only makes nix available and then drives Agda through the existing flake wrapper.
Motivation¶
The library is intended to support AI-assisted formal development (the agda-native-air tooling track) and to serve as a high-quality Agda corpus for ML training and retrieval (M8). An agent that can type-check its own proposed revisions is a prerequisite for both: it closes the loop between suggestion and verification, and it keeps any agent-authored proof terms honest before they enter the corpus. Committing the configuration makes agent onboarding reproducible and reviewable rather than ad hoc per session.
Tasks¶
- Add
.claude/settings.json. - Add
.claude/hooks/session-start.sh(mode0755). - Confirm generated artifacts stay untracked (
/.agda/,src/**/*.agdai, the generatedEverything*.agda). - (Optional) Add the
formalverificationCachix substituter to the hook for CI parity and faster warm-ups. - (Optional) Add or update
CLAUDE.mdso the agent inherits the canonical-path conventions (Setoid/canonical,Legacy/Base/frozen, Σ-type core with record bundle views, deprecation discipline).
Acceptance criteria¶
- In a fresh web session the hook provisions Nix and reports Agda 2.8.0 / standard-library 2.3.
- The agent type-checks at least one representative module through the flake wrapper with exit 0 (e.g.
nix develop --command agda src/Overture.lagda.md). -
makeregenerates the module aggregator andmake checkinvokesagdaunchanged. - No generated interface files or aggregator modules are committed.
- CI behaviour is unaffected; the hook is web-only and local
nix developis untouched.
Notes¶
- The hook is synchronous: the session waits until provisioning finishes, which prevents the agent from invoking
agdabefore it exists. The cost is ~30–80 s on a cold container and near-instant once cached. - Network discovery: the web container uses a host allowlist in which
nixos.organdinstall.determinate.systemsare unreachable butreleases.nixos.organdcache.nixos.orgare reachable; the hook fetches the installer fromreleases.nixos.orgaccordingly. - Chicken-and-egg: the hook only takes effect once it is on the checked-out branch, so the first session after merge — and any session on a branch that contains it — is provisioned automatically.
- Project-specific Claude Code skills (an Agda type-check skill, a
docs/STYLE.md-mirroring style skill) are deferred to a follow-up issue to keep this change focused on the environment.
Issue M1-12: Reorganize docs/: resolve the docs/notes vs docs/Notes case collision (#396, closed)¶
Labels:
Problem¶
docs/ holds two sibling directories whose names differ only in case — docs/notes/ and docs/Notes/. On a case-insensitive filesystem (default macOS APFS, default Windows NTFS) these two paths collide: git tracks them as distinct, but a checkout folds them into one directory, producing phantom modify/delete churn in git status and risking file clobbering on checkout. This is a portability bug, not merely a cosmetic one; it will bite any collaborator or CI runner on a case-insensitive filesystem.
The two directories are also unrelated in content:
docs/notes/holds Markdown working and design notes — currentlymilestone-signature-functors.mdandm4-5d-handoff.md. This is the correct home for prose notes and should keep its lowercase name.docs/Notes/is not notes at all: it is a LIPIcs LaTeX paper draft, "The design space of generalizing universal algebra" (Jacques Carette), together with its build assets (lipics-v2021.cls,cc-by.pdf,orcid.pdf,lipics-logo-bw.pdf). It is paper material misfiled under a "Notes" name.
Proposed structure¶
Move the LaTeX draft under docs/papers/ (where the arXiv paper and TYPES2021/ already live) and keep docs/notes/ for Markdown notes:
docs/
├── adr/ # architecture decision records (unchanged)
├── audits/ # style / quality audits (unchanged)
├── notes/ # Markdown working & design notes (unchanged; canonical home for prose notes)
├── papers/ # all LaTeX papers and their assets
│ ├── designspace/ # ← moved from docs/Notes/ (Carette "design space" LIPIcs draft + assets)
│ ├── TYPES2021/
│ └── … # arXiv paper, shared .cls / .sty / .bib / pdf
├── GITHUB_PROJECT.md
└── STYLE_GUIDE.md
The core move eliminates the docs/Notes path entirely, so the collision is resolved without a case-only rename (which would itself need a two-step git mv on a case-insensitive filesystem).
Tasks¶
-
git mv docs/Notes docs/papers/designspace(movesdesignspace.texand its four assets). - Grep the repo for references to
docs/Notes(any makefile target, link, or build script) and update them. - Record the convention in
docs/STYLE_GUIDE.md:docs/notes/is the home for Markdown notes; LaTeX papers and their assets live underdocs/papers/.
Non-goals¶
- Deduplicating the three
lipics-v2021.clscopies (underdocs/Notes/,docs/papers/, anddocs/papers/TYPES2021/). They have different contents (distinct md5sums), so consolidating them is a separate, careful task and not part of this cleanup. - Any change to
src/, or to theadr/andaudits/trees.
Labeling¶
This is repo-infrastructure and docs-governance hygiene, so it belongs in milestone M1 (home of CI, the STYLE_GUIDE, docs/adr/, and the GITHUB_PROJECT tooling), as M1-12 — the next free M1 number (M1-11 / #349 is the highest used).
Issue M1-13: Tier the type-check: the paper-specific certificates are 44% of a clean build (#515, closed)¶
Labels: enhancement, milestone-1-infra, ci, flrp-research
Description¶
Type-checking the whole library has roughly doubled in wall-clock time, and a large share of the new cost is modules that matter only to the FLRP research track and to the fin-lat-rep manuscript — above all the generated representation certificates under src/FLRP/Certificates/SmallLatticeReps/. A user of the algebra library who does not care about the finite lattice representation problem should not pay for them on every build, and a contributor waiting on make check should not either.
Measurements (this worktree, Agda 2.8.0, agda --profile=modules src/Everything.agda from an empty _build/, -M6G -A128M):
| time | share of build | |
|---|---|---|
| whole clean type-check | 395.2 s (6.6 min, 6.3 GB peak RSS) | 100 % |
FLRP.Certificates.SmallLatticeReps.* (27 modules) |
175.2 s | 44.3 % |
the other two certificates (Pilot, Group) |
3.4 s | 0.9 % |
Legacy.*, pulled in transitively by Examples.Structures and Exercises.Complexity.FiniteCSP (#322, ualib/agda-algebras#323) |
24.1 s | 6.1 % |
| core library and everything else | 192.4 s | 48.7 % |
So the census costs as much as the entire rest of the library, and it is concentrated: the four slowest certificates (SLR13 45.2 s, SLR27 29.6 s, SLR09 25.2 s, SLR33 23.6 s) are 71 % of the census total. Two further data points worth recording here, both actionable independently of this issue:
- the slowest single module in the whole library is not a certificate — it is
Classical.Structures.Lattice.Parachuteat 45.4 s (currently in review on ualib/agda-algebras#506), just ahead ofSLR13; Setoid.Subalgebras.Subdirect.Finitecosts 22.1 s, which corroborates ualib/agda-algebras#439's guess about that module from measurement rather than impression.
For scale on the other axis: the census is 36,095 lines, 39 % of all source under src/, but only 12 % of interface bytes.
Three structural facts make this cheap to fix.
- The census certificates are pure leaves. No module in
src/imports anyFLRP.Certificates.SmallLatticeReps.SLR*module — not even theFLRP.Certificatesbarrel, which contains only the checker assembly. They enter the build solely through the generatedsrc/Everything.agda, so excluding them changes no import graph and no public API. - The Makefile already has the pattern.
EverythingLegacy.agdais a second generated aggregator with its own gate, precisely so the frozenLegacy/tree is checked without being part of the canonical library. A certificate tier is the same move a second time. - Two CI cache bugs are inflating the measured cost independently of any tiering. The
Cache .agdai interface filesstep cachespath: src/**/*.agdai, but Agda 2.7+ writes interfaces to_build/<version>/agda/src/...— there are zero.agdaifiles undersrc/, so the cache saves and restores nothing. Its key also hashessrc/**/*.agda, which misses the.lagda.mdfiles that are ~99 % of the sources. Fixing those two lines is likely a larger win for CI than the tiering itself, and is worth doing first because it is independent.
Options considered¶
A. Tier the aggregator (recommended). Exclude src/FLRP/Certificates/SmallLatticeReps/** from Everything.agda, add a generated EverythingCertificates.agda over exactly that directory, and give it its own make target and its own CI job. Keeps every module in the repository and under CI, needs no file moves, touches no imports, and is trivially reversible. Keep FLRP/Certificates/{Pilot,Group}/** — two modules — in the core tier so the default build still exercises the certificate checker end to end.
A′. Move the certificates out of src/ entirely (say to certificates/), so they are artifacts rather than library modules. Architecturally tidier and the aggregator excludes them for free, but it moves 27 files, rewrites their cross-links and site paths, and needs the .agda-lib include path extended. Worth considering later; not worth it as a first step.
B. Move the certificates to UniversalAlgebra/fin-lat-rep. Cleanest audience separation, and the option to keep in view — but the costs are real and worth writing down before choosing it:
- that repository has been untouched since October 2016; it holds LaTeX, lattice lists, UACalc files, and talks, with no
.github/, no CI, no Nix, and no Agda — so the whole toolchain would have to be stood up there first; - the certificates import the library's checkers (
FLRP.Certificates,Setoid.Congruences.Certificates), so the other repository needs a pinnedagda-algebrasdependency, and version skew becomes a maintenance surface; - cross-repo breakage becomes invisible: a change to a checker's API here would be discovered late, in a repository nobody is watching, instead of by
make checkin the PR that caused it; - it gives up the atomic-PR property that FLRP roadmap § 1 explicitly chose in-repo development for ("a single PR can extend the foundation and use the extension atomically");
- it also gives up M8 corpus value — machine-checked certificates are among the most valuable training artifacts the repository has;
- and the manuscript source is itself vendored here, at
docs/papers/fin-lat-rep/SmallLatticeReps.tex, so moving only the evidence would separate the paper from its checked artifacts rather than co-locating them.
C. Make the certificates cheaper to check (worth doing regardless, and it feeds ualib/agda-algebras#439). The per-module profile attached above says where the time actually goes; candidate levers are abstract/opaque boundaries around the big tables so downstream normalization cannot unfold them, replacing compile-time from-yes (… ?) evaluation with tabulated structural proofs, and splitting the largest modules so interface caching is finer-grained. This should be a follow-up issue driven by the profile, not guesswork.
Proposal¶
Do the independent CI cache fix and option A now; open a data-driven follow-up for C; leave B on the table as the answer if the census keeps growing.
Tasks¶
- Fix the CI interface cache:
path: _build/and a key that hashessrc/**/*.lagda.mdas well assrc/**/*.agda. -
Everything.agda: exclude$(SRCDIR)/FLRP/Certificates/SmallLatticeReps/*, with the reason in the target's comment block. - New generated aggregator
EverythingCertificates.agdaover that directory, in the style ofEverythingLegacy.agda. - Targets:
make check(core + Legacy, as now, minus the census),make check-certificates(the new tier),make check-all(both). Update the Makefile header,README.md, andCONTRIBUTING.md, which currently tell contributors thatmake checktype-checks the entire library. - CI: add a
Type-check certificatesjob runningmake check-certificates, in parallel with the existing job and required byall-green. Nothing goes unchecked; core feedback arrives sooner and total wall-clock drops because the jobs run concurrently. -
make htmlandmake agda-mdkeep rendering the certificate tier, so the published site and/classic/do not lose pages. - Attach the per-module profile to ualib/agda-algebras#439 and open a follow-up for the worst offenders.
Acceptance criteria¶
-
make checkno longer type-checksFLRP/Certificates/SmallLatticeReps/**, and the measured improvement is reported in the PR. -
make check-allis green, and CI still gates on the certificate tier. - The site still renders every certificate page.
- No core-tier module imports a census certificate (guaranteed today;
make check-allwould catch a regression).
Related: ualib/agda-algebras#439 (profile type-checking times), ualib/agda-flrp#13 and ualib/agda-flrp#15 (the census that produces these certificates), ualib/agda-flrp#2 (FLRP program).
Issue M1-14: agda-algebras and its standard library under Agda 2.9.0 (#586)¶
Labels: milestone-1-infra
Description¶
Agda 2.9.0 is not released, but Agda's master declares it and the nightly prerelease builds it. Agda accepts an interface only from the same Agda, so anyone who ships this library's interfaces for 2.9.0 (an IDE, a package set) needs the library, and the standard library it depends on, to check under 2.9.0. Today the library is on Agda 2.8.0 and standard-library 2.3 (#250, whose last acceptance criterion asked for a look at the next Agda), every module --cubical-compatible --safe.
This issue finds out whether, and with which standard library, the library checks under Agda 2.9.0, and records the answer. It fixes here only what is small and checks under both 2.8.0 and 2.9.0. It does not move the pins (flake.nix, flake.lock, depend:); moving the library to 2.9.0, and to which standard library, is a separate decision once the findings are in.
What is known before the run¶
- The Agda. The nightly for commit
da66a8c75f11d10699a6b38b261efdf244b66f2a(2026-10-05), release assetAgda-da66a8c-linux.tar.xz(SHA-256fd58ff5cc94c910a129d7fe083e0cd9d8e93b277bf89d2155a040ddc3c91ce7d), a static x86-64 Linux binary that reportsAgda version 2.9.0. The nightly tag moves, so the commit is the pin. - No standard-library release is tested against 2.9.0. Agda's CI tests the standard library pinned as its
std-libsubmodule: agda-stdlib's branchagda-masterat1b7f26af(standard-library-3.0). That branch carries three fixes Agda's master needed that agda-stdlib's CHANGELOG does not record:1896499f(eta equality is no longer inferred),39631ce9(irrelevant-recomputenow needs--irrelevant-projections, an option Agda marks inconsistent, so unusable under--safe) and1b7f26af(fixity declarations removed from non-operators). The construct39631ce9removes is in v2.3'sRelation.Nullary.Recomputableand in v2.4'sData.Irrelevant, both in the import closure ofSetoid.Varieties.HSP. - 3.0 may not serve this library: the first highlight of its CHANGELOG moves standard-library modules from
--cubical-compatibleback to--without-K, and a--cubical-compatiblemodule cannot import a--without-Kone (CoInfectiveImport).
The matrix¶
Each row records the command, exit code, wall time, peak memory, how many standard-library and library modules it checked, and every error and warning by kind. The rows are as follows:
- The library's master with standard-library 2.3, under 2.9.0, as
make checkruns it (the standard library checked from source along the way). - Standard-library 2.4 under 2.9.0; then the library against 2.4 with the three commits applied, on a branch of its own, recording what breaks (a port only as far as it takes to know the size of the change).
- (2b) Standard-library 2.3 with
1896499fand1b7f26afcherry-picked and39631ce9ported by hand, then the library against it. - Standard-library 3.0 (
1b7f26af): whether one library module can import it. - The control: the flake's Agda 2.8.0 with the same flags, every module checked from source.
On the configuration that checks, under 2.9.0 and under the control: the interface sizes of Setoid.Varieties.HSP's import closure, a warm check of a module importing it, and whether the interfaces are reproducible.
Findings follow in a comment. The plan file, docs/GITHUB_PROJECT.md, needs make project-plan to pick this issue up.
Issue M1-15: Upgrade to Agda 2.9.0 and a standard library that supports it (#588)¶
Labels: milestone-1-infra
Description¶
Move the library from Agda 2.8.0 and standard-library 2.3 to Agda 2.9.0 and a standard library that supports it, as #250 moved it to 2.8.0. The investigation is #586: under the 2.9.0 nightly the library's own sources need nothing but the removal of two fixity declarations for closed operators (#587), so this upgrade is mostly the standard library and the pins.
The plan (decided 2026-10-06): the library's modules move from --cubical-compatible back to --without-K, as a change of their own, before this one (#594; #279 holds the flag strategy). That makes standard-library 3.0 the target: 3.0 is --without-K again (agda/agda-stdlib#2967, merged 2026-06-17), which a --cubical-compatible module cannot import (Agda reports CoInfectiveImport; #586, row 4) and a --without-K module can.
The preconditions, which this issue assumes, are as follows:
- The switch to
--without-K(#594) is on master. - Standard-library 3.0 is released and type-checks under the released Agda 2.9.0. As of 2026-10-06 neither is released. 3.0's development head, on agda-stdlib's
agda-masterbranch, checks under the 2.9.0 nightly (Agda's own CI); no released standard library does (2.3 and 2.4 both fail atirrelevant-recompute; #586, rows 1 and 2). - nixpkgs packages both, since the flake takes Agda and the standard library from one nixpkgs input; otherwise an
overrideAttrspin, if William chooses it.
If one is missing when this issue is picked up, record that here and stop; a patched or unreleased standard library is a downstream workaround, never this library's pin.
The size is not measured against 3.0 yet. It is 3.0's breaking changes (the Function hierarchy, _≟_ deprecated for _≡?_ and _≈?_, the components of _Respects₂_ swapped, the v1.x deprecations removed), plus the 2.4 deprecations 3.0 inherits: against 2.4 with the three agda-master fixes the library checked after changing only depend:, with 80 new deprecation warnings (five names, 16 modules; #586, row 2).
Tasks¶
- Confirm the preconditions with a run: standard-library 3.0 checks under the released Agda 2.9.0, and a library module, under
--without-K, imports it. -
flake.nixandflake.lock: a nixpkgs that provides Agda 2.9.0 and that standard library (or anoverrideAttrspinning the standard library'ssrc, as the flake's header describes); update the header comment and the shell hook's version guards (2.8.*,2.3*). -
agda-algebras.agda-lib:depend: standard-library-X.Y; keep-WnoUnsupportedIndexedMatchonly if it is still needed. - Fix what breaks, errors first; then the warnings 2.9.0 and the new standard library add, each addressed properly (a rename to the documented replacement, not a suppression). Known today: one
FixityDeclarationForNonOperatorremains, inLegacy.Base.Relations.Quotients, whoseLegacy/tree is frozen. - Port to 3.0: its breaking changes, then its deprecations, each to the documented replacement.
- Every place that names the toolchain:
README.md(badges, status, requirements),INSTALL.md,CONTRIBUTING.md(including the agda-mode version),mkdocs.yml(agda_version,stdlib_version),docs/index.md's figures (make corpus-stats),scripts/python/test_corpus_stats.py's fixtures if they must follow,.github/workflows/ci.yml's header,.github/ISSUE_TEMPLATE/bug_report.yml, and aCHANGELOG.mdentry. - CI: the Agda lane passes on the new pins; the interface cache's key follows
flake.lock, so it turns over by itself.
Acceptance criteria¶
-
nix develop --command make checkpasses under Agda 2.9.0 and the chosen standard library, every module checked from source, locally and in CI. - The warnings are the library's own deprecations and nothing else: no warning kind that 2.8.0 did not report, and none of the standard library's deprecations.
- No file names Agda 2.8.0 or standard-library 2.3 as the current target (dated records, such as the CHANGELOG and the audits, excepted).
-
make corpus-stats-checkand the docs lanes pass.
Decision, 2026-10-07: the interim pins¶
William overrode this issue's rule that a patched or unreleased standard library is never this library's pin, so that all of his Agda projects run one Agda now. The library moves to a pre-release Agda 2.9.0 (agda/agda at da66a8c, the nightly of 2026-10-05) and standard-library 2.3 with the five changes it needs under 2.9.0 (formalverification/agda-stdlib, tag v2.3-agda-2.9.0), both pinned by the flake, and the README, INSTALL.md and CONTRIBUTING.md say that the toolchain is available only through nix develop until the releases. This issue closes with that move, #598, whose description records the evidence: every module checked from source, with the same 352 Checking lines and the same 951 UserWarning positions as under 2.8.0. The plan above, the released Agda 2.9.0 with standard-library 3.0 from nixpkgs and the port to 3.0, moves to #597.
Issue M1-16: Switch every module from --cubical-compatible to --without-K (#594, closed)¶
Labels: milestone-1-infra, cubical
Description¶
Move every module of the library from --cubical-compatible back to --without-K, reversing that part of #250 (decision: William, 2026-10-06). The reasons are as follows:
- Standard-library 3.0 is
--without-K(agda/agda-stdlib#2967, merged 2026-06-17), and a--cubical-compatiblemodule cannot import a--without-Kone: Agda reportsCoInfectiveImport, under 2.8.0 as under 2.9.0 (#586, row 4). So the library cannot take 3.0, or any later standard library, until it switches; #588 (the move to Agda 2.9.0 and standard-library 3.0) depends on this issue. - The flag has no consumer. It exists to let a
--cubicalmodule import this one, and nothing does; the Cubical track of ADR-003 derives its modules by substitution, not by import, and a--cubicaltree would build on agda/cubical, not on the standard library's--without-Kmodules. #279 holds the flag strategy and the import-firewall discussion. - It costs time and bytes. Measured below: the whole library checks faster and its interfaces are smaller under
--without-K, which matters for a browser IDE that ships the interfaces.
The switch is independent of any Agda or standard-library release: it checks today under the pinned Agda 2.8.0 and standard-library 2.3 (which is --cubical-compatible; a --without-K module may import a --cubical-compatible one, as every --without-K module of the standard library imports Agda's --cubical-compatible builtins).
What is known, 2026-10-06¶
A probe on a scratch branch (22f67aa5, #587's head, plus the sweep below) under the flake's Agda 2.8.0 and standard-library 2.3, every module from source, measured against the unswept tree in the same sitting:
- The sweep is the whole change: 344 module pragmas and the Makefile's two aggregator pragmas.
make checkthen passes with the same 346Checkinglines (344 modules and two aggregators) and the same 951UserWarningpositions (the library's own deprecations), and no other warning or error. The probe keptflags: -WnoUnsupportedIndexedMatchinagda-algebras.agda-lib, so the figures are the sweep's alone. - Time, the library's 346 modules from source with the standard library's interfaces accepted, alternating runs in one sitting at a 1-minute load average of 1.95 to 1.99 before each:
--cubical-compatible85.3 and 87.7 s;--without-K74.9 and 75.6 s, 12 to 14% less. (For scale, the same check with the standard library from source too: 157.9 s at a load average of 1.00; the afternoon's runs of it took 176 to 198 s at about 2.) - Peak RSS rose: 2,095,228 and 2,095,516 KiB (about 2.0 GiB) under
--cubical-compatible, 2,713,104 and 2,713,168 KiB (about 2.6 GiB) under--without-K, both at+RTS -M6G -A128M. Not diagnosed; the pull request measures it again, with+RTS -sif it persists. - Interfaces are smaller: the whole
_buildof 346 interfaces went from 60,581,757 to 54,255,026 bytes (10.4% smaller; gzipped as one stream, 50,978,625 to 45,683,072). 326 shrank, 2 are the same size, 18 grew (those in the HSP closure by 2 to 50 bytes). The largest change:Setoid.Congruences.ChainJoin, 954,341 to 452,292 bytes. - The import closure of
Setoid.Varieties.HSP(314 modules, fromagda --dependency-graph): the library's 92 interfaces went from 18,110,993 to 15,585,129 bytes (13.9% smaller; gzipped 15,592,745 to 13,460,527), so the closure's total from 63,714,368 to 61,188,501 bytes (gzipped 54,290,430 to 52,158,240), the standard library's 212 modules being unchanged.
The runs: make AGDA=<wrapper> check in each worktree, the wrapper being the flake's Agda 2.8.0 binary with --no-default-libraries --library-file <file> --library standard-library --library agda-algebras, the file naming a from-source checkout of standard-library 2.3 and the worktree; GNU time for wall and peak RSS; Checking lines counted unanchored. The logs are kept outside the repository ($S/logs/probe-*).
The sweep itself is mechanical: all 344 modules carry the one line {-# OPTIONS --cubical-compatible --exact-split --safe #-}, and the Makefile's two aggregator pragmas (Everything.agda, EverythingLegacy.agda) are the only others. Legacy/ must switch with the rest, frozen or not: its modules import Setoid/ modules, and a --cubical-compatible module importing a --without-K one is exactly the failing direction.
Tasks¶
- The sweep: the 344 module pragmas to
{-# OPTIONS --without-K --exact-split --safe #-}, and the twoecholines in the Makefile's aggregator targets. -
agda-algebras.agda-lib: dropflags: -WnoUnsupportedIndexedMatch, since that warning exists only under--cubical-compatible. - The prose that explains or names the flag, each claim checked rather than search-and-replaced:
Overture.Basic's paragraph on the pragma (it argues for--cubical-compatibleover--without-K; it now argues the reverse, with the reasons above),Overture.Preface, and the ten modules whose prose saysFin-indexed tuples "lack η under--cubical-compatible" or that something is "unavailable under--safe --cubical-compatible" (Classical.Bundles.Magma,Classical.Bundles.Semigroup,Classical.Operations,Classical.Structures.Group.Congruences,.Power,.Product,Classical.Structures.Interpret,Setoid.Algebras.Basic,Setoid.Congruences.Lattice,Setoid.Varieties.FreeSubstitution): those are facts about--safewithout function extensionality, true under either flag, so name the right cause. - The documents that state the rule:
docs/STYLE_GUIDE.md(four pragma listings and the bullet explaining the flag),CONTRIBUTING.md(the pragma and the paragraph saying all ofsrc/uses--cubical-compatible),INSTALL.md(theUnsupportedIndexedMatchnote and the "implies full unfolding" sentence),docs/site-guide.md,scripts/audit_lagda_migration.sh's smoke-test template,scripts/python/groups/a5_simple_cert.py's generated pragma, andscripts/python/test_corpus_stats.py's fixtures (the stats read only--safe, so they pass either way; change the fixtures for consistency). - A decision record,
docs/adr/011-*.md, in the form of the others: the decision, the three reasons, the measurements, and what it means for ADR-003 (the portability discipline stays; a future--cubicaltree cannot import this one, which is #279's firewall and was the case for 3.0's standard library in any event). Leave ADR-003 as it is, with a one-line pointer to the new record. -
CHANGELOG.md: an entry under the unreleased version. - On #279: a comment that the strategy is decided here, with a link to the record; whether it closes is William's call.
Acceptance criteria¶
-
nix develop --command make checkpasses under the current pins, every module checked from source, locally and in CI, with no new warning kind (the library's ownUserWarningdeprecations are the only warnings before and after). - No pragma in
src/and no generated aggregator names--cubical-compatible;git grep -e cubical-compatiblefinds only dated records (the CHANGELOG, ADR-003, the audits and notes, the papers) and the new ADR. - The pull request's description records the time and interface-size figures of a from-source check before and after, with the load average of each run.
-
make corpus-stats-check,make docstringsand the docs lanes pass.
Non-goals¶
- Not the move to Agda 2.9.0 or to standard-library 3.0; that is #588, which needs this issue first.
- Not the Cubical track; ADR-003's discipline is unchanged, and the consequence for a future
src/Cubical/is recorded, not acted on.
Issue M1-17: Move to the released Agda 2.9.0 and standard-library 3.0 (#597)¶
Labels: milestone-1-infra
Description¶
#588 moved the library to a pre-release Agda 2.9.0 (agda/agda at da66a8c, the nightly of 2026-10-05) and standard-library 2.3 with the five changes it needs under 2.9.0 (formalverification/agda-stdlib, tag v2.3-agda-2.9.0), both pinned by the flake, by William's decision of 2026-10-07 that his Agda projects run one Agda now rather than wait for the releases. #588's own plan moves here: the released Agda 2.9.0 with standard-library 3.0, both from nixpkgs.
The preconditions are as follows:
- The switch to
--without-K(#594) is on master: done on 2026-10-07 (#595). Standard-library 3.0 is--without-Kagain, which a--cubical-compatiblemodule could not import. - Agda 2.9.0 and standard-library 3.0 are released, and 3.0 type-checks whole under the released 2.9.0:
agda --build-libraryin its root, as nixpkgs' derivation runs it. Neither is released as of 2026-10-07. - nixpkgs packages both, so that the flake can drop its
agdainput and the standard library's override and return to one nixpkgs input, as the comment at the top offlake.nixsays.
What the port will take, from a trial of 2026-10-07 under Agda master (8430299e) and the standard library its std-lib submodule pinned (3.0's development head, 1b7f26af), with the library under --without-K: 25 files (the flake, agda-algebras.agda-lib and 22 modules), changed as follows:
- a record that built
IsDecEquivalencewith the field_≟_, now_≈?_(TooManyFields, thenUnsolvedMetaVariables); - a named implicit
{i = p}toTransitive, whose binders 3.0 renamed tox y z(WrongNamedArgument); - 170 renames to 3.0's names: 3.0's
_≟_for_≡?_(theData.Fin,Data.NatandData.Boolproperties), and 2.4's_×-dec_,_→-dec_,_⊎-dec_and¬∀⟶∃¬for_×?_,_→?_,_⊎?_and¬∀⇒∃¬, whose fixities are unchanged, so that every rename is textual.
The trial's patch is kept outside the repository; redo the port against the released 3.0 rather than apply it. One trap it met: a deprecation reached through a bundle raises no warning (uses of _≟_ after open DecSetoid S using ( _≟_ ) raised none), so counting warnings does not finish the port; grep for the renamed names where they arrive through a record or bundle module.
Tasks¶
- Confirm the preconditions with a run: standard-library 3.0 checks whole under the released Agda 2.9.0.
-
flake.nixandflake.lock: drop theagdainput and the standard library'soverrideAttrs, take both from one nixpkgs input, and update the header and the standard library's guard (2.3*). -
agda-algebras.agda-lib:depend: standard-library-3.0. - Port to 3.0: its breaking changes, then its deprecations, each to the documented replacement.
- Every place that names the toolchain, as #588 listed them. The "Nix only, for now" caveat in
README.md,INSTALL.mdandCONTRIBUTING.mdgoes, andINSTALL.md's three paths without Nix move to the released versions. - CI: the Agda lane passes on the new pins.
Acceptance criteria¶
-
nix develop --command make checkpasses under the released Agda 2.9.0 and standard-library 3.0, every module checked from source, locally and in CI. - The warnings are the library's own deprecations and nothing else.
- No file names the pre-release Agda or the patched standard library as the current target (dated records, such as the CHANGELOG and the audits, excepted).
-
make corpus-stats-checkand the docs lanes pass.
Milestone 1 Dependencies¶
M1-5 is the integration node: the new README / Preface needs all the other M1 deliverables to exist before it can refer to them. M1-6 (docs/adr/) is structurally independent but is gated on M1-1 because it references the 3.0 release.
graph TD
M1_1["M1-1: Agda 2.8 / stdlib 2.3"]
M1_2["M1-2: GitHub Actions CI"]
M1_3["M1-3: Community files"]
M1_4["M1-4: STYLE_GUIDE.md"]
M1_5["M1-5: README / Preface"]
M1_6["M1-6: docs/adr/"]
M1_1 --> M1_2
M1_1 --> M1_3
M1_1 --> M1_4
M1_1 --> M1_6
M1_2 --> M1_5
M1_3 --> M1_5
M1_4 --> M1_5
---¶
Milestone 2 — Consolidation¶
Issue M2-1: Freeze Base/, adopt Setoid/ as canonical (#256, closed)¶
Labels: milestone-2-consolidation, breaking-change
Description¶
The decision is ratified: Setoid/ is the canonical development tree for 2.0; Base/ is frozen and moved to Legacy/Base/. Rationale: Setoid/ is fully constructive (no extensionality postulates); it matches the stdlib Algebra.Bundles idiom which simplifies bridges; maintaining two trees indefinitely doubles every theorem's cost; Setoid/ already contains the definitive HSP proof.
Note: Base/ remains in the repo — frozen, not deleted — for posterity and as a reference. Parts may be ported back to Setoid/ or Cubical/ as needed.
This is a breaking change for downstream users of Base/. Announce prominently in the 2.0 CHANGELOG.
Tasks¶
- Move
src/Base/→src/Legacy/Base/. - Update
src/agda-algebras.agdato re-exportLegacy.Basewith a deprecation note. - Add
DEPRECATED.mdinLegacy/Base/explaining the status and pointing users toSetoid/. - Write ADR
docs/adr/001-setoid-as-canonical.md. - Announce in CHANGELOG.
Acceptance criteria¶
-
src/Base/no longer exists at the old path. -
src/Legacy/Base/exists and type-checks. - ADR-001 is merged.
- CHANGELOG entry documents the move prominently.
Issue M2-2: Consolidate parallel implementations within Legacy/Base/Structures (#257, closed)¶
Labels: milestone-2-consolidation
Description¶
Base.Structures.Basic defines multi-sorted structures as records; Base.Structures.Sigma.* does the same thing as Σ-types. They are parallel implementations of the same concept, each with its own Products, Congruences, Homs, Isos. Since Base/ is frozen (see M2-1), scope is limited to Legacy cleanup, but worth doing for clarity.
Tasks¶
- Pick one formulation (record or Σ) as canonical within Legacy.
- Add conversion functions where they don't already exist.
- Update internal uses to the canonical form.
- Keep the non-canonical form under a distinct namespace with a deprecation note.
Acceptance criteria¶
-
Legacy/Base/Structures/has a single canonical implementation of each concept. - The non-canonical namespace is clearly marked deprecated.
Issue M2-3: Remove Base.Structures.Graphs0 (unused experimental duplicate) (#258, closed)¶
Labels: milestone-2-consolidation
Description¶
src/Base/Structures/Graphs0.agda is not exported public from Base/Structures.agda and appears to be an abandoned experimental earlier version of Base/Structures/Graphs.agda.
Tasks¶
- Investigate for any downstream dependency on
Graphs0. - If none, delete the file.
- If still referenced, rename to
Graphs.Alternativewith a comment explaining the distinction.
Acceptance criteria¶
-
Graphs0is either deleted or clearly renamed with documentation. - Library still type-checks.
Issue M2-4: Designate a canonical HSP proof; consolidate the others (#259, closed)¶
Labels: documentation, milestone-2-consolidation
Description¶
The library contains three proofs of Birkhoff's HSP theorem:
Base.Varieties.FreeAlgebras.Birkhoff(original Base-tree proof).Setoid.Varieties.HSP.Birkhoff(definitive setoid proof).Demos.HSP.Birkhoff(self-contained pedagogical version for TYPES 2021).
Tasks¶
- Designate
Setoid.Varieties.HSP.Birkhoffas canonical. - Keep
Demos.HSPas the self-contained pedagogical presentation (it was created for TYPES 2021 and remains valuable as a teaching artifact). - Move
Base.Varieties.FreeAlgebras.Birkhoffinto Legacy (implicit via M2-1, but cross-reference explicitly). - Add cross-references among the three so a reader starting at any of them can find the canonical statement.
- Update paper citations in
docs/papers/.
Acceptance criteria¶
-
Setoid.Varieties.HSP.Birkhoffis marked canonical in its module header. -
Demos.HSPcontains a reference to the canonical version. - The paper citation table is up to date.
Issue M2-5: CI gap: Legacy.Base tree is not type-checked by make check (#301, closed)¶
Labels: milestone-2-consolidation, ci
Description¶
The current Everything.agda target in the Makefile excludes $(SRCDIR)/Legacy/* from the generated Everything.agda file. Consequence: make check does not type-check the Legacy/Base/* tree. This was discovered while reviewing PR #300 (M2-1, freeze Base/ as Legacy/Base/); the freeze itself does not introduce the gap, but it makes the gap operationally significant for the first time, since several Setoid/* modules now import from Legacy.Base/* (per ADR-001 §Consequences and the partial-replacement note in DEPRECATED.md).
The exclusion is correct in spirit: Everything is the canonical library, and Legacy/ is by definition not canonical. Including Legacy modules in Everything would (i) clutter the rendered HTML with import Legacy.Base.Structures.Sigma.Congruences next to import Setoid.Varieties.HSP as if they were peers, and (ii) bind the canonical aggregator's import list to content scheduled for eventual removal.
The fix is a second aggregator, EverythingLegacy.lagda.md, that exists purely as a CI gate over src/Legacy/. It is not part of the canonical library and is not rendered to HTML. This pattern generalizes correctly: when Setoid/ itself becomes Legacy in 4.0 (per ADR-003, to be ratified at M5-1), EverythingLegacy.lagda.md will pick up the demoted Setoid tree without any change to Everything.lagda.md semantics.
Tasks¶
- Add an
EverythingLegacy.lagda.mdtarget to the Makefile that generates an aggregator over$(SRCDIR)/Legacy/. - Wire
EverythingLegacy.lagda.mdintomake checkso that bothEverythingandEverythingLegacyare type-checked on every invocation. - Update
.gitignoreifEverything.lagda.mdis gitignored (treat the legacy aggregator the same way). - Update
.github/workflows/ci.ymlto ensure CI invokes the same target (likely no change needed if CI already callsmake check, but verify). - Add a header comment to the generated
EverythingLegacy.lagda.mdexplaining why it exists and that it is not part of the canonical library. - Add
! -name 'EverythingLegacy.lagda.md'to theEverything.lagda.mdtarget'sfindexclusions (preempts the bootstrap loop where each aggregator tries to import the other). - Document the split in
docs/STYLE_GUIDE.md(one paragraph: "what does Everything mean?") so future contributors understand the convention.
Acceptance criteria¶
-
make checkon a cleannix developshell type-checks every.lagda.mdand.agdafile undersrc/, includingsrc/Legacy/. - CI on a fresh PR fails if any
Legacy/Base/*module fails to type-check. - The rendered HTML at https://ualib.org continues to advertise
Everythingas the canonical library, with noLegacy.Base.*entries cluttering its module list. - STYLE_GUIDE.md documents the convention.
Issue M2-6: Extract Setoid-canonical foundations from Legacy.Base (#303, closed)¶
Labels: milestone-2-consolidation
Description¶
The M2-1 freeze (#256, PR #300) surfaced an unaesthetic structural fact: several Setoid/* modules import basic definitions from what is now Legacy.Base.*. After the freeze these imports are type-correct but contradict the framing of Setoid/ as canonical — the canonical tree should not depend on the legacy tree.
This issue extracts the affected definitions into a self-sufficient location. Should land before M3-1 (#260, Classical/ scaffold) so the new layer builds on a clean Setoid/.
Affected imports (audit at M2-1 merge)¶
From grep -rn 'open import Legacy.Base' src/Setoid after the freeze:
Setoid.Algebras.Congruences←Legacy.Base.Relations(0[_],_|:_,Equivalence)Setoid.Algebras.Products←Legacy.Base.Functions(proj,projIsOnto,IsSurjectiverenamedonto)Setoid.Homomorphisms.Factor←Legacy.Base.Relations(kernelRel)Setoid.Homomorphisms.Kernels←Legacy.Base.Relations(kerRel,kerRelOfEquiv)Setoid.Relations.Quotients←Legacy.Base.Relations([_],Equivalence)Setoid.Subalgebras.Subuniverses←Legacy.Base.Relations(Im_⊆_),Legacy.Base.Terms(Term,ℊ,node)Setoid.Terms.Basic,Setoid.Terms.Operations,Setoid.Terms.Properties←Legacy.Base.Terms(Term)Setoid.Varieties.EquationalLogic,Setoid.Varieties.FreeAlgebras,Setoid.Varieties.Preservation,Setoid.Varieties.Properties,Setoid.Varieties.SoundAndComplete←Legacy.Base.Terms(Term,ℊ)
Tasks¶
- For each imported definition (
Term,Equivalence,kernelRel,kerRel,kerRelOfEquiv,Im_⊆_,[_],0[_],_|:_,proj,projIsOnto,IsSurjective), decide its canonical destination:Overture/(if it's foundational and shared acrossSetoid/andClassical/), or a newSetoid/module (if it's setoid-specific and was simply mis-located inBase/historically).Termis the most consequential decision point: it likely belongs inOverture/because bothSetoid/andClassical/will need it. - Move each definition to its canonical destination. Preserve prose comments.
- Update the affected
Setoid/*imports. - Add a
{-# WARNING_ON_USAGE #-}pragma to the legacy definition pointing at the new home. - Update
Legacy/Base/DEPRECATED.mdto record the relocation under Category A with the new canonical path. -
make checkpasses.
Acceptance criteria¶
-
grep -rn 'open import Legacy.Base' src/Setoidreturns no matches. -
grep -rn 'open import Legacy.Base' src/Classical(when M3-1 lands) returns no matches. -
make checkpasses includingEverythingLegacy.lagda.md. - DEPRECATED.md reflects the relocations.
Why now¶
- M3-1 (#260) introduces
Classical/, which will exerciseSetoid/'s self-sufficiency aggressively. Landing this work first meansClassical/doesn't inherit the Legacy.Base dependency. - Definitions that need to live in
Overture/are easier to relocate before they have many call sites;Termin particular is referenced widely already.
Non-goals¶
- Porting Category-B legacy modules (tracked in #TBD parent).
- Reorganizing
Setoid/more broadly.
References¶
- ADR-001 —
docs/adr/001-setoid-as-canonical.md(Consequences section, "Setoid/ is not yet self-sufficient") - M2-1 — #256
- M3-1 — #260 (depends on this)
Issue M2-7: Port orphan Base modules to canonical paths (#302, closed)¶
Labels: milestone-2-consolidation
Description¶
The M2-1 freeze (#256, PR #300) moved src/Base/ to src/Legacy/Base/ and partitioned the legacy modules into three categories in DEPRECATED.md. This issue was the parent tracking the Category-B ports — modules without a canonical replacement at the freeze point.
Scope (as filed)¶
Only orphans whose canonical destination is a port to Setoid/, Overture/, or Examples/. The two large groups of Category-B content explicitly out of scope:
Legacy.Base.Structures.*(16 modules) — superseded wholesale by theClassical/tree (#260, M3-1). Closed by M3 deliverables; no child issue here.Legacy.Base.Equality.*(4 modules, Category C) — retired by construction inSetoid/, no replacement planned. No child issue.
Resolution¶
All seven children closed. Final dispositions:
- M2-7a (#305) —
Legacy.Base.Adjunction.*(4 modules) →Overture.Adjunction.*. Promoted toOverture/rather thanSetoid/because the abstract order-theoretic content is needed identically acrossSetoid/,Classical/, andCubical/. - M2-7b (#306) —
Legacy.Base.Categories.*(2 modules) →Examples.PolynomialFunctors.*. Relocated toExamples/rather than ported into the canonical universal-algebra core; established the precedent now documented in DEPRECATED.md for Category-A relocations toExamples/. - M2-7c (#307) —
Legacy.Base.Complexity.*(3 modules) →Setoid.Complexity.*. Landed in M2 rather than deferred to M9; M9-2 (#281) and M7-1 (#274) now consume the canonical path directly. - M2-7d (#308) —
Legacy.Base.Relations.Continuous→Setoid.Relations.Continuous, with the arity-many indexed-setoidcongdesign documented in the module header. Landed in M2; M9-1 (#282) and M9-2 (#281) now consume the canonical path directly. - M2-7e (#309) —
Legacy.Base.Relations.Properties→Setoid.Relations.Properties. - M2-7f (#310) —
Legacy.Base.Functions.Transformers→Examples.FunctionTypeBijections. Audit against stdlib'sFunction.*confirmed the content was illustrative bijection-construction material rather than a load-bearing API; sameExamples/precedent as M2-7b. - M2-7g (#311) —
Legacy.Base.Varieties.Invariants→Setoid.Varieties.Invariants.
For each port, the legacy module was retained with a {-# WARNING_ON_USAGE #-} pragma naming the canonical home and the closing-issue number; removal is scheduled for v3.1, giving downstream users one full minor cycle to migrate.
Acceptance criteria¶
- Every orphan listed above has a closed child issue (port complete).
- DEPRECATED.md's Category B table contains no row whose
Tracking issuecolumn reads#TBD. - The only Category-B residual content is the
Structures.*subtree (handled by M3); theEquality.*subtree is Category C (no replacement planned).
References¶
- ADR-001 —
docs/adr/001-setoid-as-canonical.md - DEPRECATED.md —
src/Legacy/Base/DEPRECATED.md - M2-1 — #256
- Children — #305, #306, #307, #308, #309, #310, #311
Issue M2-7a: Port Legacy.Base.Adjunction.* to canonical paths (#305, closed)¶
Labels: milestone-2-consolidation, design-discussion
Description¶
Port the four-module Legacy.Base.Adjunction.* subtree (aggregator + Closure + Galois + Residuation) to canonical paths. Child of #302.
The destination is not yet decided — adjunction / Galois-connection / residuation content sits at an awkward intersection of universal algebra (where it is consumed: closure operators induce algebraic closure systems, congruence-extending Galois connections appear in clone theory) and pure order theory (where the abstract definitions naturally belong). The destination decision is part of this issue.
Destination options¶
Setoid.Adjunction/— keeps the content next to its universal-algebra consumers. Disadvantage: adjunctions are not specifically setoid-flavored; ifClassical/ever grows order-theoretic content (lattices, posets) the same definitions will want to live there too, and we'd have duplication.Classical.Order.Adjunction/— fits if M3-5 (#264, Lattice) and any plannedClassical.Order.*infrastructure absorb the abstract order-theoretic content. Disadvantage: requiresClassical/order infrastructure to land first.Overture/Adjunction/— fits if the content is genuinely foundational and used acrossSetoid/,Classical/, and (eventually)Cubical/. Disadvantage:Overture/is small and intentionally narrow; expanding its scope deserves its own design discussion.
The third option is probably premature; the first two are both defensible. Recommend deciding Setoid.Adjunction/ for v3.0 and reconsidering the location for v4.0 alongside any Classical.Order/ work.
Tasks¶
- Decide the destination. Record briefly in this issue.
- Port
Legacy.Base.Adjunction.Closureto<Destination>.Closure. - Port
Legacy.Base.Adjunction.Galoisto<Destination>.Galois. - Port
Legacy.Base.Adjunction.Residuationto<Destination>.Residuation. - Port the aggregator
Legacy.Base.Adjunctionto<Destination>. - Add
{-# WARNING_ON_USAGE #-}pragmas to each legacy module pointing at the canonical home. - Update
Legacy/Base/DEPRECATED.md: move all four rows from Category B to Category A. - Confirm
make checkandEverythingLegacyboth pass.
Acceptance criteria¶
- Four canonical-path modules exist and type-check.
- Four
Legacy.Base.Adjunction.*modules carryWARNING_ON_USAGEpragmas. - DEPRECATED.md reflects the move; no
#TBDcells remain for the Adjunction rows.
References¶
- Parent — #302
- ADR-001 —
docs/adr/001-setoid-as-canonical.md - DEPRECATED.md —
src/Legacy/Base/DEPRECATED.md - Possible future consumer — #282 (M9-1, Scott-continuous DCPOs). Not a blocker; flagged because the destination decision should keep M9-1's plausible needs in mind (Galois connections between predicates and operations on DCPOs are natural M9-1 territory).
Issue M2-7b: Port Legacy.Base.Categories.* to canonical paths (#306, closed)¶
Labels: milestone-2-consolidation, design-discussion
Description¶
Port the two-module Legacy.Base.Categories.* subtree (aggregator + Functors) to canonical paths. Child of #302.
The destination is not obvious. agda-algebras is a universal-algebra library, not a category-theory library; the Agda ecosystem already has agda-categories as a comprehensive category-theory development. Two questions:
- Do we need this content in agda-algebras, or should it be redirected to
agda-categorieswith a thin shim re-exporting whatever agda-algebras code presently consumes?src/Examples/Categories/Functors.lagda.mdis the only known consumer in this repo. - If kept, where:
Setoid.Categories/, a new top-levelCategories/tree (probably wrong; we don't want to be a category-theory library), or pulled intoOverture/(probably wrong; too narrow there)?
This issue's first deliverable is the destination decision, not the port.
Tasks¶
- Audit the content of
Legacy.Base.Categories.*againstagda-categoriesto determine whether equivalent functionality already exists upstream. - If equivalent functionality exists upstream: file a follow-up to remove
Legacy.Base.Categories.*outright, redirectingsrc/Examples/Categories/Functors.lagda.md(#304) toagda-categoriesinstead of porting. Close this issue with the redirection decision recorded. - If equivalent functionality does not exist upstream: decide on a destination (
Setoid.Categories/, or kept inLegacy.Base.Categories/indefinitely with the Category B rationale clarified to "stays in Legacy because no canonical home exists in the universal-algebra scope of this library"). Port ifSetoid.Categories/; document if "stays in Legacy." - Update
Legacy/Base/DEPRECATED.mdaccordingly: either move both rows to Category A (port landed), or reword the Category B rows to reflect "stays in Legacy" status (no port planned), or move to a new "Category D — relocated upstream" if redirected. - Confirm
make checkandEverythingLegacyboth pass.
Acceptance criteria¶
- A destination decision is recorded in this issue.
- DEPRECATED.md reflects the resolution; no
#TBDcells remain for the Categories rows. - If a port lands, the canonical-path modules type-check; if relocated upstream,
Examples/Categories/Functors.lagda.mdis updated accordingly.
References¶
- Parent — #302
- Examples migration — #304
agda-categories— https://github.com/agda/agda-categories- Adjacent — #283 (M9-3, exploratory coalgebra). M9-3's reading may surface a need for some categorical infrastructure; if so, this issue's destination decision should be reconsidered with M9-3's findings in mind. Not a current blocker — M9-3 is exploratory and may conclude no formalization is warranted.
Issue M2-7c: Port Legacy.Base.Complexity.* to canonical paths (#307, closed)¶
Labels: milestone-2-consolidation, milestone-9-apps
Description¶
Port the three-module Legacy.Base.Complexity.* subtree (aggregator + Basic + CSP) to canonical paths. Child of #302.
Scheduled with M9. Issue #274 (M7-1, "Extend Complexity module beyond Basic and CSP") is the substantive sequel that grows this content significantly; this issue's scope is the canonical-path migration only, not the extension. Order: this issue first, then #274 builds on the canonical-path version.
Destination¶
The natural destination is Setoid.Complexity/, mirroring the existing Legacy.Base.Complexity/ shape. Open question — to be settled in this issue — is whether the eventual home should be Setoid.Complexity/ (consistent with current naming) or a top-level Complexity/ tree (parallel to Classical/, since complexity is a domain rather than a flavor of universal algebra). Recommendation: Setoid.Complexity/ for v3.0 to minimize churn; revisit at the v4.0 Cubical canonicalization moment.
Tasks¶
- Confirm the destination — recommended
Setoid.Complexity/. - Port
Legacy.Base.Complexity.BasictoSetoid.Complexity.Basic. - Port
Legacy.Base.Complexity.CSPtoSetoid.Complexity.CSP. - Port the aggregator
Legacy.Base.ComplexitytoSetoid.Complexity. - Add
{-# WARNING_ON_USAGE #-}pragmas to each legacy module pointing at the canonical home. - Update
Legacy/Base/DEPRECATED.md: move all three rows from Category B to Category A; correct the destination column to the agreed canonical name. - Confirm
make checkandEverythingLegacyboth pass.
Acceptance criteria¶
- Three canonical-path modules exist and type-check.
- Three
Legacy.Base.Complexity.*modules carryWARNING_ON_USAGEpragmas. - DEPRECATED.md reflects the move; no
#TBDcells remain for the Complexity rows.
Why M9 milestone?¶
Setoid.Complexity/ is the foundation for M9-2 (#281, infinitary CSP), which is squarely complexity content built on the existing Base.Complexity development. M7-1 (#274) is the extension of the same content for finite-template CSP; that issue depends on the canonical-path version landing first. M9-1 (#282, Scott-continuous DCPOs) does not depend on this port — its dependencies are on Relations.Continuous (#308) and on the order/lattice infrastructure flowing from M3-5 (#264) — and is listed below only as a sibling M9 issue, not as a consumer.
References¶
- Parent — #302
- M7-1 (extend Complexity) — #274
- M9-2 (infinitary CSP) — #281
- Exercises migration — #304 (depends on this for
FiniteCSP.lagda.md)
Issue M2-7d: Port Legacy.Base.Relations.Continuous to canonical paths (#308, closed)¶
Labels: milestone-2-consolidation, milestone-9-apps
Description¶
Port Legacy.Base.Relations.Continuous to a canonical path. Child of #302.
The Continuous relation API — relations of arbitrary arity type rather than fixed natural-number arity, with arity-many indexed-setoid families — is the foundation of three M9 issues (#281, #282, #283). Until this port lands, M9 work depends on Legacy.Base/, contradicting the framing of Setoid/ as canonical.
Destination question¶
Two options:
Setoid.Relations.Continuous— fits the currentSetoid.Relations.{Discrete,Quotients}naming. Disadvantage: continuous relations are not specifically setoid-flavored; the abstract definition is at the order-theoretic / domain-theoretic level.Overture.Relations.Continuous(or newOverture.Continuous/) — fits if continuous relations are foundational acrossSetoid/,Classical/, andCubical/. Likely the right long-term home, but expandingOverture/deserves its own design moment.
Recommendation: port to Setoid.Relations.Continuous for v3.0 (mechanical, low-friction); revisit Overture/ placement during v4.0 Cubical canonicalization when the same definitions will have to be expressible there too.
The destination decision should harmonize with #303 (M2-6, Extract Setoid-canonical foundations from Legacy.Base), which makes parallel decisions for Term, kerRel, and other foundational definitions. If #303 lands first and routes those to Overture/, this issue should follow suit; if #303 keeps them in Setoid/, the same logic applies here.
Why this is a non-trivial port¶
Unlike most of Category A, where the propositional-equality version maps mechanically onto the setoid version by passing ≡-setoid A, the Continuous API has substantive subtlety: the "respects-the-setoid-equivalence" condition for arity-many arguments needs careful design. The natural setoid version of f : (i : I) → A i → B has a cong that takes a proof of (i : I) → A i ≈ A' i and produces f A ≈ f A', but the indexing makes the standard setoid-function shape not quite right. The port should consult the design used by the underlying stdlib Function.Indexed.* machinery (if any) and harmonize.
Tasks¶
- Decide the destination. Recommended
Setoid.Relations.Continuousfor v3.0. - Design the setoid-respecting interface for indexed continuous relations. Document briefly in the module header.
- Port
Legacy.Base.Relations.Continuousto the chosen destination, with the indexed-setoid design in place. - Add a
{-# WARNING_ON_USAGE #-}pragma to the legacy module. - Update
Legacy/Base/DEPRECATED.md: move the row to Category A. - Confirm
make checkandEverythingLegacyboth pass.
Acceptance criteria¶
- Canonical-path module exists, type-checks, and has a prose comment block documenting the indexed-setoid-respecting design.
-
Legacy.Base.Relations.Continuouscarries aWARNING_ON_USAGEpragma. - DEPRECATED.md reflects the move; no
#TBDcell remains for the Continuous row. - M9-1 (#282) and M9-2 (#281) can import from the canonical path without changes.
References¶
- Parent — #302
- M2-6 (Setoid foundations extraction) — #303. Sibling issue setting precedent for
Overture/vs.Setoid/placement of foundational definitions. - M9-1 — #282
- M9-2 — #281
- M9-3 — #283
- Exercises migration — #304 (depends on this for
FiniteCSP.lagda.md)
Issue M2-7e: Port Legacy.Base.Relations.Properties to Setoid.Relations.Properties (#309, closed)¶
Labels: milestone-2-consolidation
Description¶
Port Legacy.Base.Relations.Properties to Setoid.Relations.Properties. Child of #302.
Smallest of the M2-7 children — a single module port whose canonical destination is unambiguous (the Setoid.Relations.* subtree exists and has matching Discrete / Quotients siblings). Scheduled as an M2 follow-up.
The M2-1 inventory found no consumers of Base.Relations.Properties outside src/Base/ itself — no src/Setoid/, src/Examples/, or src/Exercises/ module imports it. The migration is therefore localized: porting the module and updating the Setoid.Relations aggregator covers it.
Tasks¶
- Port
Legacy.Base.Relations.PropertiestoSetoid.Relations.Properties. Migration is mechanical when content is propositional-equality-based; replace_≡_arguments with the algebra's setoid equivalence as needed. - Update
Setoid.Relations(the aggregator) to re-exportSetoid.Relations.Propertiespublic. - Add a
{-# WARNING_ON_USAGE #-}pragma toLegacy.Base.Relations.Properties. - Update
Legacy/Base/DEPRECATED.md: move the row from Category B to Category A; remove the partial-replacement note from theLegacy.Base.Relationsaggregator row in Category A (now covered). - Confirm
make checkandEverythingLegacyboth pass.
Acceptance criteria¶
-
Setoid.Relations.Propertiesexists and type-checks. -
Legacy.Base.Relations.Propertiescarries aWARNING_ON_USAGEpragma. - DEPRECATED.md no longer flags
Setoid.Relationsas a partial replacement (assumingContinuousis also resolved per #308; otherwise, the partial-replacement note is updated to reference onlyContinuous). - No
#TBDcell remains for the Relations.Properties row.
References¶
- Parent — #302
- Companion — #308 (Relations.Continuous; the other half of why
Setoid.Relationsis currently partial)
Issue M2-7f: Port Legacy.Base.Functions.Transformers to canonical paths (#310, closed)¶
Labels: milestone-2-consolidation, design-discussion
Description¶
Port Legacy.Base.Functions.Transformers to a canonical path. Child of #302.
Single-module port; destination is the design-discussion piece.
Like #309, the M2-1 inventory found no consumers of Base.Functions.Transformers outside src/Base/ itself. This makes the "drop entirely if all definitions have stdlib equivalents" path cheap — no internal call sites need migration.
Destination question¶
Legacy.Base.Functions.Transformers contains function-transformer combinators (currying, uncurrying, point-free composition variants, possibly others — to be confirmed by audit). Two destinations:
Setoid.Functions.Transformers— fits the currentSetoid.Functions.{Injective,Surjective,Inverses}naming. Disadvantage: function transformers are propositional (not setoid-flavored) by nature; the canonical home is probably stdlib'sFunction.Base/Function.Definitions.- Redirect to stdlib — audit the content; if stdlib already provides equivalent combinators, remove the module rather than porting it, and update any consumers to import from stdlib.
Recommendation: audit first; the right answer is likely "stdlib redirect" for most of the module, with Setoid.Functions.Transformers covering whatever residual content has no stdlib analog.
Tasks¶
- Audit
Legacy.Base.Functions.Transformerscontent against stdlib'sFunction.BaseandFunction.Construct.*. - For each definition, decide: stdlib redirect, port to
Setoid.Functions.Transformers, or drop entirely (if an unused experimental). - If any content survives the audit: port to
Setoid.Functions.Transformers; updateSetoid.Functionsaggregator to re-export. - If no content survives: remove
Legacy.Base.Functions.TransformersfromLegacy/Base/DEPRECATED.mdand from the Legacy build (or move to a new "Category D — removed in 3.x" section if the deletion deserves a record). - Add a
{-# WARNING_ON_USAGE #-}pragma to the legacy module pointing at the new home (or at the appropriate stdlib module per definition). - Confirm
make checkandEverythingLegacyboth pass.
Acceptance criteria¶
- Audit results recorded in this issue (per-definition disposition).
- DEPRECATED.md reflects the resolution; no
#TBDcell remains for the Functions.Transformers row. -
make checkpasses.
References¶
- Parent — #302
- stdlib
Function.*— https://agda.github.io/agda-stdlib/master/Function.html
Issue M2-7g: Port Legacy.Base.Varieties.Invariants to Setoid.Varieties.Invariants (#311, closed)¶
Labels: milestone-2-consolidation
Description¶
Port Legacy.Base.Varieties.Invariants to Setoid.Varieties.Invariants. Child of #302.
Single-module port; destination is unambiguous (the Setoid.Varieties.* subtree is already canonical and contains the HSP development).
The M2-1 inventory found no consumers of Base.Varieties.Invariants outside src/Base/ itself. Plausible future consumer: M3-7 (#266, expand Examples/), where varieties-as-invariants results characterizing classical structure classes are natural worked examples.
Tasks¶
- Port
Legacy.Base.Varieties.InvariantstoSetoid.Varieties.Invariants. Migration is mechanical when content reasons up to propositional equality on the algebra carrier; replace with the algebra's setoid equivalence as needed. - Update
Setoid.Varieties(the aggregator) to re-exportSetoid.Varieties.Invariantspublic. - Add a
{-# WARNING_ON_USAGE #-}pragma toLegacy.Base.Varieties.Invariants. - Update
Legacy/Base/DEPRECATED.md: move the row from Category B to Category A. - Confirm
make checkandEverythingLegacyboth pass.
Acceptance criteria¶
-
Setoid.Varieties.Invariantsexists and type-checks. -
Legacy.Base.Varieties.Invariantscarries aWARNING_ON_USAGEpragma. - DEPRECATED.md reflects the move; no
#TBDcell remains for the Varieties.Invariants row.
References¶
- Parent — #302
- Possible future consumer — #266 (M3-7, expand Examples/ with classical structures). Not a current dependency.
Issue M2-8: Migrate src/Examples and src/Exercises imports to canonical paths (#304, closed)¶
Labels: milestone-2-consolidation
Description¶
After the M2-1 freeze (#256, PR #300), three files outside src/Legacy/ still import from Legacy.Base.*:
src/Examples/Structures/Basic.lagda.md— importsLegacy.Base.StructuresandLegacy.Base.Structures.Basic.src/Examples/Structures/Signatures.lagda.md— importsLegacy.Base.Structures.Basic.src/Exercises/Complexity/FiniteCSP.lagda.md— importsLegacy.Base.Structures.Basic,Legacy.Base.Structures.Homs(and, until this PR,Legacy.Base.Relations.Continuous).
These imports are technically correct after the rename, but the example/exercise should exercise the canonical library, not the legacy one. Each needs to migrate to whichever destination its content lands at.
Status¶
- Categories.Functors. Resolved under #306 (M2-7b) by relocation to
Examples.PolynomialFunctors.Functors; the oldsrc/Examples/Categories/directory was removed. The stale\input{../latex/Examples.Categories.Functors}indocs/papers/EverythingFunc.texis fixed by this PR. Setoid.Relations.Continuousimport inFiniteCSP. Landed in this PR (the canonical Continuous destination was finalized under #308 / M2-7d).Legacy.Base.Structures.*imports. Blocked on M3-1 (#260,Classical/scaffold). Tracked in follow-ups M2-8b (Structures examples) and M2-8c (FiniteCSP structures + homs).
Tasks¶
- Migrate the
Continuousimport inExercises/Complexity/FiniteCSP.lagda.md. - Fix the stale
Examples.Categories.FunctorsLaTeX\input. - Decide the fate of
Examples/Structures/{Basic,Signatures}.lagda.mdonce M3-1 lands — migrate toClassical/or fold into the M3-7 (#266) examples. Tracked in M2-8b. - Migrate the two
Legacy.Base.Structures.*imports inExercises/Complexity/FiniteCSP.lagda.mdonce M3-1 lands. Tracked in M2-8c.
Acceptance criteria¶
-
grep -rn 'Examples\.Categories' src/ docs/returns no matches. -
grep -rn 'open import Legacy.Base' src/Examples src/Exercisesreturns no matches (deferred to M2-8b + M2-8c after M3-1). -
make checkpasses.
References¶
- M2-1 — #256
- M2-7b (Categories port) — #306
- M2-7d (Continuous port) — #308
- M3-1 — #260
- M3-7 — #266
- Parent port-tracking issue — #302
Issue M2-8b: Update imports in submodules of Examples.Structures (#322)¶
Labels: milestone-2-consolidation, blocked-upstream
Description¶
The two example modules src/Examples/Structures/Basic.lagda.md and src/Examples/Structures/Signatures.lagda.md still import signature and structure from Legacy.Base.Structures.{Basic,...}. Their canonical home depends on M3-1 (#260, Classical/ scaffold), which has not yet landed.
The pedagogical content here is heterogeneous:
- Finite signatures
S∅,S1,S001,S021, ... inSignatures.lagda.md. These are foundational examples consumed byExercises.Complexity.FiniteCSP. Natural canonical home:Classical.Signatures.*once M3-1 lands. Migration is mechanical. SL(3-element meet-semilattice) inBasic.lagda.md. Naturally re-expressed againstClassical.Structures.Semilattice(M3-5 #264) once that lands. Could fold into the M3-7 (#266) examples program.NAE3SAT(2-element ternary NAE-3-SAT relational structure) inBasic.lagda.md. Genuinely relational — the current M3 plan is algebraic (operations only) — so this content has no natural destination in the plannedClassical/tree. Two options: (a) keep a bare-types relational-structures example, perhaps underExamples/RelationalStructures/; (b) defer to a futureClassical.Relational/extension.
Tasks¶
- Decide the per-example destination once M3-1 lands.
- Migrate signatures examples to
Classical.Signatures.*if M3-1's signature API supports it directly. - Migrate or rewrite
SLagainstClassical.Structures.Semilattice(depends on M3-5). - Resolve
NAE3SAT: relocate, rewrite, or delete. - Update
Exercises/Complexity/FiniteCSP.lagda.md'sExamples.Structures.Signaturesconsumer accordingly (M2-8c is the immediate downstream).
Dependencies¶
- Blocked by M3-1 (#260).
- Benefits from M3-5 (#264) for the semilattice example.
- M3-7 (#266) may subsume the
SLexample.
References¶
- Parent — #304 (M2-8)
- M3-1 — #260
- M3-5 — #264
- M3-7 — #266
Issue M2-8c: Fix imports in Exercises.Complexity.FiniteCSP (#323)¶
Labels: milestone-2-consolidation, blocked-upstream
Description¶
src/Exercises/Complexity/FiniteCSP.lagda.md still imports signature, structure, and hom from Legacy.Base.Structures.{Basic,Homs} after the M2-8a partial closure (#304). These imports are gated on M3-1 (#260, Classical/ scaffold) for the same reasons as M2-8b.
The exercise uses the bare-types relational-structures API (relational signatures S021, the structure 𝐹 𝑅 record with non-trivial rel field, and hom for the resulting relational structures). As noted in M2-8b, the planned Classical/ tree is currently algebraic-only, so this migration depends on either:
- M2-8b resolving the relational-structures destination question, or
- M3 being extended to cover relational structures (a
Classical.Relational/subtree).
Tasks¶
- Coordinate with M2-8b on the destination of relational-structures content.
- Migrate the
signature,structure,homimports inFiniteCSP.lagda.mdto the chosen destination. - Remove the
TODO(#M2-8c)marker added in M2-8a.
Acceptance criteria¶
-
grep -rn 'open import Legacy.Base' src/Exercisesreturns no matches. -
make checkpasses.
References¶
- Parent — #304 (M2-8)
- Sibling — M2-8b
- M3-1 — #260
Milestone 2 Dependencies¶
M2-1 (freeze Base/) is the fork point: everything else in this milestone is internal cleanup within what becomes Legacy/Base/, and all three depend on the move happening first. M1-1 is shown dashed to indicate it's an upstream dependency from a different milestone.
graph TD
M1_1["M1-1: Agda 2.8 / stdlib 2.3"]:::ext
M2_1["M2-1: Freeze Base"]
M2_2["M2-2: Consolidate Base.Structures"]
M2_3["M2-3: Remove Graphs0"]
M2_4["M2-4: Canonical HSP"]
M2_5["M2-5: EverythingLegacy CI"]
M2_6["M2-6: Extract Setoid foundations"]
M2_7["M2-7: Port orphans (parent)"]
M2_7a["M2-7a: Adjunction"]
M2_7b["M2-7b: Categories"]
M2_7c["M2-7c: Complexity"]
M2_7d["M2-7d: Continuous"]
M2_7e["M2-7e: Relations.Properties"]
M2_7f["M2-7f: Functions.Transformers"]
M2_7g["M2-7g: Varieties.Invariants"]
M2_8["M2-8: Examples/Exercises migration"]
M1_1 --> M2_1
M2_1 --> M2_2
M2_1 --> M2_3
M2_1 --> M2_4
M2_1 --> M2_5
M2_1 --> M2_6
M2_1 --> M2_7
M2_7 --> M2_7a
M2_7 --> M2_7b
M2_7 --> M2_7c
M2_7 --> M2_7d
M2_7 --> M2_7e
M2_7 --> M2_7f
M2_7 --> M2_7g
M2_7a --> M2_8
M2_7b --> M2_8
M2_7c --> M2_8
M2_7d --> M2_8
classDef ext fill:#f0f0f0,stroke:#999,stroke-dasharray: 4 3,color:#555
---¶
Milestone 3 — Classical structures layer¶
Issue M3-1: Introduce the Classical/ tree — Signatures, Theories, Structures, Bundles, Small (#260, closed)¶
Labels: milestone-3-classical, design-discussion
Description¶
The library has no formalized classical algebraic structures despite this being a long-stated vision. This issue creates the scaffold; subsequent issues add specific structures.
Ratified design decisions (to be recorded in docs/adr/002-classical-layer.md):
- Each classical structure
Xis Σ-typed at the core:X α ρ = Σ[ 𝑨 ∈ Algebra 𝑆ₓ α ρ ] 𝑨 ⊨ Eₓ. The mathematical reading "X is an algebra equipped with a proof it satisfies the X-theory" motivates Σ over record for classical structures. The coreAlgebratype stays a record. - A parallel record-typed "bundle view" in
Classical/Bundles/Xmatches the stdlibAlgebra.Bundlesidiom for interop. - Built on
Setoid/(notBase/). A helperfromPropEq : Type α → ... → X α αlets users build classical structures from propositional-equality-based definitions without explicit Setoid wrapping. - Designed for Cubical portability. Equations stated purely in terms of
Algebra.Domain's equivalence — never reaching for Setoid-specific features without a Cubical analog. WhenCubical/becomes canonical in 3.0, the port should be mechanical. - Two levels of specificity per structure: polymorphic core (
Classical.Structures.X) and level-fixed veneer (Classical.Small.Structures.X) for the commonℓ₀case.
Tasks¶
- Create the directory skeleton:
src/Classical/
Classical.agda
Signatures/
Theories/
Structures/
Bundles/
Small/Structures/
- Add placeholder modules that type-check.
- Write
Classical.agdathat re-exports everything. - Write
docs/adr/002-classical-layer.mdrecording the design decisions.
Acceptance criteria¶
- Scaffold type-checks.
-
Classical.agdare-exports the empty scaffold cleanly. - ADR-002 is merged.
Issue M3-1a: Scaffold the Classical/ tree — umbrella files for all five subtrees (#326, closed)¶
Labels: documentation, milestone-3-classical
Parent: #260 (M3-1)
Description¶
This issue introduces the directory layout and umbrella files for the Classical/ tree, per the design committed in ADR-002. It is scaffolding only: no concrete structure (Magma, Semigroup, Monoid, …) lands here. Concrete structures are tracked under separate M3-2…N issues, each shipping the five-file quintuple (Signatures + Theories + Structures + Bundles + Small) per ADR-002 for one structure.
Six umbrella files land:
src/Classical.lagda.md— top-level umbrella for theClassicaltreesrc/Classical/Signatures.lagda.md— umbrella for per-structure signaturessrc/Classical/Theories.lagda.md— umbrella for per-structure equational theoriessrc/Classical/Structures.lagda.md— umbrella for per-structure Σ-typed coressrc/Classical/Bundles.lagda.md— umbrella for per-structure stdlib-shaped record bundlessrc/Classical/Small.lagda.md— umbrella for per-structure level-fixed veneers
Each umbrella file gets a standard module header with the canonical "This is the [Classical.X][] module of the Agda Universal Algebra Library" prose preamble, an ADR-002 cross-reference, a prose-schema explanation of what the subtree will contain (so a reader landing on Classical/Signatures.lagda.md knows it's the home of per-structure signature definitions, even before any concrete signature exists), and an empty public re-export block ready to grow as M3-2…N land structures.
The top-level Classical.lagda.md umbrella additionally cross-references the parallel structure of Setoid/ (per ADR-001) so the relationship between the two trees is visible from the entry point.
The library aggregator agda-algebras.lagda.md already mentions Classical/ as a planned tree under ADR-002; that reference is updated from "planned, M3" to active wording with a link to this scaffold, and the existing open import Classical line is uncommented (or added, if currently absent).
The Everything.agda and EverythingFunc.agda generators are updated to walk the new subtree.
Non-goals¶
- No concrete structure (
Magma,Semigroup,Monoid,Group,Lattice,Ring, …) lands here; those are M3-2…N. - No shared infrastructure (
fromPropEq, named projection helpers likeDomain/Signature/equations, generic Classical-flavored equational reasoning) lands here. The right shapes for those helpers emerge from M3-2 (Semigroup) and will be pulled up into shared locations only once they have at least one consumer. Premature abstraction here is the failure mode this issue explicitly avoids. - No bundle-bridge infrastructure to stdlib lands here; that is M3-3.
- No update to
Legacy.Base.Structures.*deprecation notices; the structures-superseded-by-Classical relocation is per-structure and tracked on the M3-2…N issues.
Tasks¶
- Create
src/Classical.lagda.mdwith the top-level module header, ADR-001/ADR-002 cross-references, a brief prose explanation of the five-subtree quintuple pattern, and an empty re-export block. - Create
src/Classical/Signatures.lagda.md,src/Classical/Theories.lagda.md,src/Classical/Structures.lagda.md,src/Classical/Bundles.lagda.md,src/Classical/Small.lagda.md, each with module header + ADR-002 cross-reference + subtree-purpose prose + empty re-export block. - Update
src/agda-algebras.lagda.mdto activate theClassical/mention (replace "planned, M3" with active wording linking to ADR-002 and to this scaffold). - Update the
Everything.agda/EverythingFunc.agdabuild target so the new files are walked bymake check. - Update
README.mdlibrary-structure section to drop "planned, M3" from theClassical/bullet. - Record under
CHANGELOG.md[Unreleased] / Added.
Acceptance criteria¶
- All six umbrella files exist with proper module headers and ADR-002 cross-references.
-
make checkpasses (the empty re-export blocks should type-check trivially). -
agda-algebras.lagda.md,README.md, andCHANGELOG.mdreflect the activation. - No concrete structure or shared helper lands; the diff is pure scaffolding.
References¶
- Parent — #260 (M3-1).
- Design — ADR-002.
- Foundation — ADR-001.
- Long-term portability target — ADR-003.
- Downstream — M3-2 (Semigroup, the first concrete structure landing under the scaffold), M3-3 (stdlib bundle bridges).
Issue M3-2: Classical.Operations and Classical.Equations infrastructure (#330, closed)¶
Labels: milestone-3-classical, design-discussion
Description¶
This issue introduces the two shared-infrastructure modules that every concrete Classical/X structure will depend on: Classical.Operations, holding the per-arity Curry/Uncurry helpers that bridge the foundational tuple-indexed operation form (I → A) → A with the curried user-facing form A → A → A; and the seed of Classical.Equations (or Classical.Identities.lagda.md — name TBD in PR), holding generic equation builders parametric in a signature and operation symbols.
Per ADR-002 v2 §1, tuple-indexed operations live in Setoid.Algebras and downstream meta-theory; curried operations are the user-facing form across Classical/. Per ADR-002 v2 §3, generic equation builders form the syntactic dual of stdlib's Algebra.Definitions and feed the equational-logic substrate (Modᵗ) for every concrete theory.
Landing this infrastructure before any concrete structure means M3-3 (Magma) is purely about signature mechanics, M3-4 (Semigroup) is purely about adding one equation, and so on. Each per-structure issue is a small composition rather than a re-derivation.
This issue is the renumbered predecessor of what was originally M3-2 (Semigroup); the M3-2 issue body was reformulated to M3-4 after the v2 ADR.
Design decisions¶
These are the conventions established here; the same applies to every per-structure file that consumes this infrastructure.
Curry/Uncurryhelpers. One pair per arity:Curry₀/Uncurry₀for nullary,Curry₁/Uncurry₁for unary,Curry₂/Uncurry₂for binary. Higher arities added as needed (Lattice in M3-7 may wantCurry₃for the absorption-law statement; defer the decision until then). Each helper is a two-line definition; the file is short.- Fin n η-bridge containment. The Fin 2 η-failure under
--cubical-compatibleis contained insideUncurry₂andCurry₂— at the use site, an(I → A) → Aoperation appears asA → A → Aand the wrapping/unwrapping is invisible. Per-structure files never writepair-style helpers inline. - Generic equation builders. Parametric in signature
S : Signature 𝓞 𝓥(orSignature ℓ₁ ℓ₂if the abstract over levels is undesirable; finalize during PR) and in operation symbols withinS, with arity-conformance evidence as a≡ Fin nargument. Inventory for M3-2: Associative : (f : OperationSymbolsOf S) → ArityOf f ≡ Fin 2 → ∀ {X} → X → X → X → Term X × Term XCommutative : (f : OperationSymbolsOf S) → ArityOf f ≡ Fin 2 → ∀ {X} → X → X → Term X × Term XLeftIdentity / RightIdentity : binary op + nullary op + their arity proofs → ∀ {X} → X → Term X × Term XLeftInverse / RightInverse : binary op + nullary identity op + unary inverse op + arity proofs → ∀ {X} → X → Term X × Term XIdempotent : (f : OperationSymbolsOf S) → ArityOf f ≡ Fin 2 → ∀ {X} → X → Term X × Term XDistributesOverˡ / DistributesOverʳ : two binary ops + their arity proofs → ∀ {X} → X → X → X → Term X × Term XAbsorbs : two binary ops + their arity proofs → ∀ {X} → X → X → Term X × Term X
This inventory covers every equation in Th-Magma, Th-Semigroup, Th-Monoid, Th-Group, Th-Semilattice, Th-Lattice, Th-Semiring, Th-Ring. Builders for less-uniform equations (e.g., the medial law) deferred until a structure needs them.
+ Self-documenting signature projections. This file also seeds OperationSymbolsOf and ArityOf aliases in Overture.Signatures (per ADR-002 v2 §1). Two-line addition; bracket notation remains everywhere it already appears.
+ Notation rename ̂ → ^ (per ADR-002 v2 §7). Add WARNING_ON_USAGE to the existing ̂ definition in Setoid.Algebras.Basic; introduce ^ as the new canonical infix. Per-tree policy: new Classical/ code uses ^ exclusively; existing Setoid/ code is not retroactively renamed.
Tasks¶
Core infrastructure files¶
-
src/Classical/Operations.lagda.md—Curry₀/Uncurry₀,Curry₁/Uncurry₁,Curry₂/Uncurry₂with prose explaining the design intent. -
src/Classical/Equations.lagda.md— the generic equation builders above, with prose introducing the file as the syntactic dual ofAlgebra.Definitionsand citing Bryant 1982 for the historical motivation that distinguishes syntactic from evaluated equation collections. -
src/Classical.lagda.mdumbrella —open import Classical.Operations publicandopen import Classical.Equations public.
Signature-projection aliases¶
- Update
src/Overture/Signatures.lagda.mdto exportOperationSymbolsOfandArityOf. Definitionally identical to the existing∣ 𝑆 ∣and∥ 𝑆 ∥aliases; no behavioral change.
Notation rename¶
- Update
src/Setoid/Algebras/Basic.lagda.mdto introduce_^_alongside_̂_, with aWARNING_ON_USAGE _̂_pragma announcing v3.1 removal. Add an ADR-002 §7 cross-reference in the module-header prose.
Documentation¶
- Module-header prose in
Classical.OperationsandClassical.Equationsdocumenting the design intent normatively, so M3-3 / M3-4 / M3-5 / M3-6 authors have a single reference for the conventions they're consuming. - Cross-reference
Classical.Equationsindocs/STYLE_GUIDE.mdunder a new section on "Generic equation builders for classical structures." -
CHANGELOG.md[Unreleased] / Addedentry.
Non-goals¶
- No concrete structure (Magma, Semigroup, Monoid, …) lands here. Those are M3-3 onward.
- No bundle-bridge infrastructure beyond what
Curry/Uncurryenables. Per-structure bundle bridges land with their structures. - Higher-arity
Curry/Uncurryhelpers (Curry₃, Curry₄, …) are added only when a concrete structure requires them. - Generic equation builders beyond the inventory above are added per-need.
Acceptance criteria¶
- All three new files (
Classical.Operations,Classical.Equations, and theClassical.lagda.mdumbrella update) type-check undermake check. -
OperationSymbolsOfandArityOfaliases reduce definitionally to the bracket forms —OperationSymbolsOf S ≡ ∣ S ∣andArityOf {S} f ≡ ∥ S ∥ fboth inhabited byrefl. - The
WARNING_ON_USAGE _̂_pragma fires in a test module that imports the old notation, and^is available as the new canonical notation. ExistingSetoid/code continues to type-check (the warning is non-fatal). - Module-header prose in
Classical.OperationsandClassical.Equationsis normative enough that a contributor authoringClassical.Magmafrom scratch can do so without consulting this PR. - CHANGELOG entry under
[Unreleased] / Added.
References¶
- Parent — #260 (M3-1).
- Scaffold predecessor — #326 (M3-1a).
- Design — ADR-002 v2 §1, §3, §7.
- Downstream — M3-3 (Magma, first consumer of this infrastructure), M3-4 (Semigroup, first equation-bearing consumer), M3-5 (stdlib bridges), M3-6/M3-7/M3-8 (Monoid/Group, Lattice, Ring).
- Empirical motivation — the M3-2 (old) Semigroup load-test in branch
261-m3-2-classical-semigroup, whosecong (Interp 𝑨)bridges andassignmentplumbing live as evidence of what this infrastructure exists to remove. - Reference for the syntactic-vs-evaluated equation distinction — R. Bryant, The laws of finite pointed groups, Bull. London Math. Soc. 14 (1982), 119–123.
Issue M3-3: Classical.Magma (#331, closed)¶
Labels: enhancement, milestone-3-classical
Description¶
After [M3-2] (#330) lands, add Magma as the pattern-setting first concrete classical structure under Classical/. Magma is the right starting structure precisely because its equational theory is empty: this isolates the signature mechanics (operation-symbol naming, arity convention, signature assembly, signature-to-algebra interpretation) from the equation mechanics of subsequent structures. Every signature convention established here propagates to Semigroup (M3-4), Monoid (M3-6), Group (M3-6), Lattice (M3-7), Ring (M3-8).
Per ADR-002 v2 §5, a structure with empty equational theory is encoded as Magma α ρ = Algebra α ρ directly — no Σ-wrapping over a trivial ⊤-typed proof obligation. Subsequent structures with equations follow the Σ[ 𝑨 ∈ Algebra α ρ ] 𝑨 ⊨ Th-X pattern.
This issue is the renumbered analog of the pattern-setting role that the original M3-2 (Semigroup) was meant to play. The original M3-2 conflated signature mechanics with equation mechanics; the v2 ADR splits them out.
Design decisions¶
These are normative for every subsequent structure (Semigroup in M3-4, Monoid + Group in M3-6, Lattice in M3-7, Ring in M3-8). Per ADR-002 v2.
- Signature representation. Named operator via a one-constructor data type:
data Op-Magma : Type where ∙-Op : Op-Magma. Constructor-naming convention<symbol>-Op(hyphen-separated, capital O). Reserves the bare symbol for use-site infix sugar overCurry₂ (∙-Op ^ _). - Arity function.
ar-Magma ∙-Op = Fin 2. Naming convention:ar-<Structure>for the arity function of<Structure>'s signature. - Signature value.
Sig-Magma : Signature lzero lzerodefined asSig-Magma = Op-Magma , ar-Magma. Hyphenated long-form name per ADR-002 v2 §7; the original draft's𝑆ₘₐsubscript form is not adopted. - No theory file. Magma has no equations, so no
src/Classical/Theories/Magma.lagda.mdfile is created. The umbrellaClassical.Theoriesdoes not import a Magma theory. Subsequent structures with theories will introduce their ownTheories/X.lagda.mdfiles. - Σ-typed core absent.
Magma α ρ = Algebra α ρ(after openingSetoid.Algebras {𝑆 = Sig-Magma}). No⊨obligation since the theory is empty. This is the only structure in the hierarchy with this property; from Semigroup onward, structures are Σ-typed. - Named accessors next to the core.
Domain,Carrier,_∙_defined alongsideMagma α ρto offset Σ/record-projection ergonomic cost._∙_ : (𝑴 : Magma α ρ) → Carrier 𝑴 → Carrier 𝑴 → Carrier 𝑴defined as𝑴 ∙ a b = Curry₂ (∙-Op ^ 𝑴) a b. Per ADR-002 v2 §1, this surfaces the operation in user-facing curried form; the tuple-indexed∙-Op ^ 𝑴form lives below the user interface. fromOpshape. Per-structure:fromOp : (A : Type α) (_·_ : A → A → A) → Magma α α. No equation arguments because Magma's theory is empty. Subsequent structures'fromOp-family constructors add an equation argument per equation in their theory.- Morphisms. No per-structure invariant required: a magma morphism is definitionally an algebra homomorphism between the underlying
Algebra Sig-Magma-algebras. Per ADR-002 v2 §5, this applies uniformly across the hierarchy. - Worked-example placement. In sibling
src/Examples/Classical/Magma.lagda.md, paralleling ADR-002 v2 §5's policy.
Tasks¶
Core four-file quintuple (no theory file — see design decisions)¶
-
src/Classical/Signatures/Magma.lagda.md—Op-Magma,ar-Magma,Sig-Magma : Signature lzero lzero. -
src/Classical/Structures/Magma.lagda.md: - the type-alias core
Magma α ρ = Algebra α ρinsideopen Setoid.Algebras {𝑆 = Sig-Magma}, - named accessors
Domain,Carrier,_∙_, - the
fromOphelper. -
src/Classical/Bundles/Magma.lagda.md— record matchingAlgebra.Bundles.Magmafrom stdlib 2.3, conversion functions⟨_⟩ₘₐ,⟪_⟫ₘₐ, pointwise round-trip lemma per ADR-002 v2 §6. -
src/Classical/Small/Structures/Magma.lagda.md— level-fixed veneerMagma = Classical.Structures.Magma.Magma lzero lzero, plus the small-casefromOp.
Worked example¶
-
src/Examples/Classical/Magma.lagda.md—(ℕ, _+_)asClassical.Small.Structures.Magma.Magma, constructed viafromOp. File-header prose flags this as the home of all future magma-specific examples. No further example demands beyond this one for M3-3.
Umbrella updates¶
- Update
src/Classical/Signatures.lagda.mdtoopen import Classical.Signatures.Magma public. - Update
src/Classical/Structures.lagda.mdtoopen import Classical.Structures.Magma public. - Update
src/Classical/Bundles.lagda.mdtoopen import Classical.Bundles.Magma public. - Update
src/Classical/Small/Structures.lagda.mdtoopen import Classical.Small.Structures.Magma public. Create this aggregator if it does not exist. - Update
src/Examples/Classical.lagda.mdtoopen import Examples.Classical.Magma. Create this umbrella if it does not exist.
Documentation¶
- Module-header prose in
Classical/Structures/Magma.lagda.mddocuments the conventions established here normatively, so future structures (Semigroup in M3-4, Monoid in M3-6, …) have a single normative reference for signature mechanics. Explicitly: hyphen-separated<symbol>-Opconstructor convention,ar-<Structure>arity-function convention,Sig-<Structure>signature-value convention,_∙_ = Curry₂ (∙-Op ^ _)user-facing curried-accessor convention,fromOp-family constructor convention. -
CHANGELOG.md[Unreleased] / Addedentry.
Non-goals¶
- No equational theory. Magma's defining feature is the empty theory; structures with equations are M3-4 onward.
- No
Classical/Theories/Magma.lagda.md. The umbrellaClassical.Theoriesremains empty after M3-3 lands; first concrete theory file is Semigroup's in M3-4. - No generic equation builders. Those are M3-2.
- No magma homomorphisms beyond the observation that they are definitionally algebra homomorphisms.
- No free magma, magma varieties as a sub-class of varieties of
Sig-Magma-algebras, presentations, term rewriting. All later. - Additional worked examples beyond
(ℕ, +). TheExamples.Classical.Magmafile is the right home for these as they accumulate.
Acceptance criteria¶
- All new files type-check under
make check. - The worked example
ℕ-magmainExamples.Classical.Magmatype-checks. - The interpretation of
∙-Opinℕ-magmareduces definitionally to_+_— no opacity from thefromOpconstruction or from theCurry₂wrapping. Discharged byrefl. - The bridge to
Algebra.Bundles.Magmaround-trips onℕ-magmapointwise: for alla, b : ℕ, the round-tripped operation applied toa, bequalsa + b. Discharged byreflon the curried form. Pointwise round-trip per ADR-002 v2 §6; not propositional≡on the Σ-type. - Module-header prose in
Classical/Structures/Magma.lagda.mddocuments the design conventions clearly enough that a contributor writingClassical/Structures/Semigroup.lagda.md(M3-4) from scratch could do so without consulting this PR's discussion. - CHANGELOG entry under
[Unreleased] / Added.
References¶
- Parent: [M3-1] #260
- Scaffold predecessor: [M3-1a] #326
- Predecessor: [M3-2] #330
- Successor: [M3-4] Semigroup #261 (first equation-bearing structure consuming this signature pattern).
- Sibling: [M3-5] #262 (stdlib bundle bridges)
- Design: ADR-002 v2 §1, §5, §7, §8.
- Stdlib target for the bundle bridge:
Algebra.Bundles.Magmain standard-library 2.3.
Issue M3-4: Classical.Semigroup (#261, closed)¶
Labels: enhancement, milestone-3-classical
Description¶
After [M3-3] #331 (Magma) lands, add Semigroup as the first concrete classical structure with a non-empty equational theory. Following ADR-002 v2 §5, a semigroup is the Σ-typed structure Semigroup α ρ = Σ[ 𝑨 ∈ Algebra α ρ ] 𝑨 ⊨ Th-Semigroup over the same signature Sig-Magma introduced by Magma — semigroups and magmas share a signature; semigroups are precisely those magmas whose binary operation is associative.
This issue is the reformulated body of #261 (originally M3-2). The original body — which positioned Semigroup as the pattern-setting first structure with per-structure SemigroupVar enums and Σ-typed cores — is superseded by the v2 ADR. The original branch 261-m3-2-classical-semigroup is retained in repository history as evidence of the load test that motivated the v2 revisions.
Design decisions¶
These are normative for every subsequent equation-bearing structure (Monoid in M3-6, Group in M3-6, …) and consume the conventions established in M3-2 (infrastructure) and M3-3 (Magma). Per ADR-002 v2.
- Signature reuse. Semigroup uses the magma signature
Sig-Magmadirectly — there is noSig-Semigroup. Subsequent structures that add operations (Monoid adds an identity element, Group adds an inverse) get their own signature; structures that only add equations over a predecessor's signature reuse the predecessor's signature. - Equational theory representation. Indexed form per
Setoid.Varieties.EquationalLogic.Modᵗ:data Eq-Semigroup : Type where assoc : Eq-Semigroup, withTh-Semigroup : Eq-Semigroup → Term (Fin 3) × Term (Fin 3)mappingassocto the associativity term-pair via the generic builderAssociative ∙-Op refl 0F 1F 2FfromClassical.Equations(introduced in M3-2). (OpenClassical.Equationswith the parameters fixed:open Classical.Equations.??? {𝑆 = Sig-Magma} {X = Fin 3}at the top ofClassical/Theories/Semigroup.lagda.md.) - Variable carrier
Fin 3. Per ADR-002 v2 §2. No per-structureSemigroupVar-style enum. Variable patterns at use sites are0F,1F,2FfromData.Fin.Patterns. - Σ-typed core.
Semigroup α ρ = Σ[ 𝑨 ∈ Algebra α ρ ] Modᵗ Th-Semigroup 𝑨insideopen Setoid.Algebras {𝑆 = Sig-Magma}. Local_⊨_alias forModᵗ Th-Semigroupis permitted but should spell out the codomain type explicitly to avoid the meta-resolution pitfall identified in the original M3-2 load test ((Eq-Semigroup → Term (Fin 3) × Term (Fin 3)), not_— the underscore lets Agda's unifier wander into the equational-logic substrate and the resulting error message points atModᵗrather than at the alias). - Named accessors in a
Semigroup-Opmodule. Following the [M3-3] precedent (whereMagma-Ophouses magma's named accessors so thatopen Magma-Op 𝑴bringsa ∙ binto scope at the use site),Semigroup-Op {α ρ} (𝑺 : Semigroup α ρ)is a named parametric module exposing_∙_, andequations. The first is re-exported through the forgetful functor viaopen Magma-Op (semigroup→magma 𝑺) public using (_∙_). This pattern — each<Structure>-Opmodule additively re-exports its predecessor's<Weaker>-Opaccessors through the forgetful projection — is the normative inheritance idiom for the whole hierarchy; subsequentMonoid-Op,Group-Op,Lattice-Op,Ring-Opfollow the same template.equations : Modᵗ Th-Semigroup (semigroup→magma 𝑺)is the new addition exposing the satisfaction proof.DomainandCarrierare not placed inSemigroup-Op; they remain accessible through the foundation's blackboard-bold accessors𝔻[ semigroup→magma 𝑺 ]and𝕌[ semigroup→magma 𝑺 ], which makes name clashes with stdlib bundle fields less likely. fromPropEqshape. Per-structure:fromPropEq : (A : Type α) (_·_ : A → A → A) (·-assoc : ∀ a b c → (a · b) · c ≡ a · (b · c)) → Semigroup α α. Pull-up to a shared location deferred until Monoid (M3-6) confirms the shape generalizes — premature shared abstraction is the failure mode #326's non-goals warn against.fromPropEqfactors throughfromOp.fromPropEq A _·_ ·-assoc = fromOp A _·_ , <Th-Semigroup proof>, reusing M3-3'sfromOprather than rebuilding the underlying algebra. This makes the forgetful acceptance criterion discharge byrefland is the normative shape for every subsequentfromPropEq-family constructor (Monoid's factors through Semigroup's, etc.).semigroup→magmaforgetful.semigroup→magma : Semigroup α ρ → Magma α ρdefined alongside the Σ-typed core, simplyproj₁. Per ADR-002 v2 §5, forgetful projections are how the "a semigroup is a magma" inheritance manifests; subsequent structures define analogous forgetfuls (monoid→semigroup,group→monoid, etc.).- Bundle bridge. Bidirectional
⟨_⟩ˢᵍ/⟪_⟫ˢᵍtoAlgebra.Bundles.Semigroupfrom stdlib 2.3, with a pointwise round-trip lemma per ADR-002 v2 §6. The Fin 2 η-bridge is contained inCurry₂/Uncurry₂fromClassical.Operations; per-structure bridge files do not write inlinepair-style wrappers. The superscript subscript-mnemonicˢᵍreplaces theₛₘform of the original draft; the analogous Magma bridge is renamed⟨_⟩ᵐᵃ/⟪_⟫ᵐᵃ(fromₘₐ) for hierarchy-wide uniformity, since the natural "sg" mnemonic for Semigroup has no subscript-g. - Worked-example placement.
src/Examples/Classical/Semigroup.lagda.md, alongside the Magma example from M3-3.
Tasks¶
Core four-file quintuple¶
-
src/Classical/Theories/Semigroup.lagda.md—Eq-Semigroup,Th-Semigroup(composesAssociative ∙-Op refl 0F 1F 2F). -
src/Classical/Structures/Semigroup.lagda.md: - the Σ-typed core,
- the
semigroup→magmaforgetful projection, - the
Semigroup-Opnamed accessor module exposing_∙_(via the forgetful) andequations, - the
fromPropEqhelper. -
src/Classical/Bundles/Semigroup.lagda.md— bidirectional bridge toAlgebra.Bundles.Semigroupwith pointwise round-trip. -
src/Classical/Small/Structures/Semigroup.lagda.md— level-fixed veneer.
Worked example¶
-
src/Examples/Classical/Semigroup.lagda.md—(ℕ, +)as aClassical.Small.Structures.Semigroup.Semigroup, constructed viafromPropEqfrom stdlib's+-assoc.
Umbrella updates¶
- Update
src/Classical/Theories.lagda.mdtoopen import Classical.Theories.Semigroup public. First concrete theory module. - Update
src/Classical/Structures.lagda.mdtoopen import Classical.Structures.Semigroup public. - Update
src/Classical/Bundles.lagda.mdtoopen import Classical.Bundles.Semigroup public. - Update
src/Classical/Small/Structures.lagda.mdtoopen import Classical.Small.Structures.Semigroup public. - Update
src/Examples/Classical.lagda.mdtoopen import Examples.Classical.Semigroup.
Documentation¶
- Module-header prose in
Classical/Structures/Semigroup.lagda.mddocuments the equation-bearing-structure conventions established here normatively, complementing the signature-mechanics prose inClassical/Structures/Magma.lagda.mdfrom M3-3. -
CHANGELOG.md[Unreleased] / Addedentry.
Non-goals¶
- Pull-up of
fromPropEqto a shared location. Deferred until at least Monoid (M3-6) confirms the shape generalizes. - Pull-up of named accessors and forgetful projections to a shared location. Same policy.
- Generic bundle-bridge infrastructure beyond the per-structure conversion functions. M3-5.
- Semigroup homomorphisms beyond
semigroup→magma-via-Setoid.Homomorphisms. Per ADR-002 v2 §5. - Free semigroups, semigroup varieties as a sub-class of varieties of
Sig-Magma-algebras, presentations, term rewriting, decidability of the word problem. All later. - Additional worked examples beyond
(ℕ, +).
Acceptance criteria¶
- All new files type-check under
make check. - The worked example
ℕ-semigrouptype-checks. - The interpretation of
∙-Opinℕ-semigroupreduces definitionally to_+_. Discharged byreflon the curried form. - The bridge to
Algebra.Bundles.Semigroupround-trips onℕ-semigrouppointwise. Discharged byreflon the curried form per ADR-002 v2 §6. - The forgetful
semigroup→magma (ℕ-semigroup)equalsℕ-magma(from M3-3) propositionally. Discharged byrefl. This holds becausefromPropEqis implemented as(fromOp A _·_) , <proof of Th-Semigroup>, factoring the underlying-algebra construction through M3-3'sfromOpso thatsemigroup→magma ∘ fromPropEq A _·_ _ ≡ fromOp A _·_definitionally. - Module-header prose in
Classical/Structures/Semigroup.lagda.mddocuments the equation-bearing-structure conventions normatively. - CHANGELOG entry under
[Unreleased] / Added.
References¶
- Parent: [M3-1] #260.
- Scaffold predecessor: [M3-1a] #326.
- Predecessors: [M3-2] (infrastructure) #330, [M3-3] (Magma) #331.
- Sibling: [M3-5] (stdlib bundle bridges) #262.
- Design: ADR-002 v2 §2, §3, §4, §5, §6.
- Empirical motivation: the original #261 branch
261-m3-2-classical-semigroup, whose Σ-typed-with-SemigroupVardesign surfaced the issues that the v2 ADR addresses. - Equational-logic substrate:
src/Setoid/Varieties/EquationalLogic.lagda.md(Modᵗ). - Equation builder:
Associativeinsrc/Classical/Equations.lagda.md([M3-2]). - Stdlib target for the bundle bridge:
Algebra.Bundles.Semigroupin standard-library 2.3.
Issue M3-5: Bridges between Classical.Structures and Algebra.Bundles (#262, closed)¶
Labels: milestone-3-classical, stdlib-bridge
v3 amendment (2026-05-21)¶
Following the M3-4 precedent (Magma and Semigroup bridges landed inside #331 and #261), the Monoid, CommutativeMonoid, Group, and AbelianGroup bundle bridges move into [M3-6] #263 alongside their structures. The bridge is a thin record-shuffle once each -Op module exposes its laws in curried form, so it belongs in the same PR as the structure that produces those laws.
Applying that rule uniformly, every remaining bundle bridge lands with its owning structure issue. This issue is consequently reduced to a tracking issue: it records the cross-cutting round-trip policy and the per-structure ownership map, and holds no implementation tasks of its own.
Round-trip policy (normative, applies to every bridge)¶
The pointwise round-trip policy from ADR-002 v2 §6 applies uniformly. No per-structure bundle bridge claims a propositional Σ-equality round-trip; the round-trip is stated pointwise on the carrier in the structure's underlying setoid equivalence. Each bridge ships a roundtrip- lemma to that effect, and a stdlib concrete instance round-trips through the bridge in the owning issue's worked example.
Bridge ownership map¶
- Magma →
Algebra.Bundles.Magma— landed in [M3-3] #331. - Semigroup →
Algebra.Bundles.Semigroup— landed in [M3-4] #261. - CommutativeSemigroup →
Algebra.Bundles.CommutativeSemigroup— UNASSIGNED; fold into [M3-6] #263. - Monoid, CommutativeMonoid, Group, AbelianGroup →
Algebra.Bundles.{Monoid,CommutativeMonoid,Group,AbelianGroup}— [M3-6] #263. - Semilattice, Lattice →
Algebra.Bundles/Algebra.Lattice.Bundles— [M3-7] #264. Lattice bridges to bothAlgebra.Bundles.LatticeandAlgebra.Lattice.Bundles.Lattice. - ~~Semiring~~, Ring, CommutativeRing →
Algebra.Bundles.{~~Semiring~~,Ring,CommutativeRing}— [M3-8] #265. (~~Semiring~~ was never in M3-8's scope and was not implemented; deferred to a later milestone. Ring and CommutativeRing landed in #265.)
Acceptance criteria¶
- This issue carries no code. Each bridge's type-checking and round-trip acceptance is owned by the structure issue listed above.
- The round-trip policy text above is mirrored in ADR-002 v2 §6 so the policy survives even if this tracker is later closed.
Issue M3-6: Classical structures — Monoid, CommutativeMonoid, Group, AbelianGroup (#263, closed)¶
Labels: milestone-3-classical, help-wanted
v2 amendment (2026-05-17)¶
Renumbered [M3-4] → [M3-6] following revision of ADR-002 v2.
Scope adjustment per ADR-002 v2 §5: each structure is self-contained over its own signature, with forgetful projections for inheritance. Concretely:
Sig-Monoidadds a nullary identity-element symbolε-Op(arityFin 0) toSig-Magma.Th-Monoidincludesassoc,id-l,id-r. Forgetfulmonoid→semigroup.Sig-Groupadds a unary inverse symbol⁻¹-Op(arityFin 1) toSig-Monoid.Th-Groupincludesassoc,id-l,id-r,inv-l,inv-r. Forgetfulgroup→monoid(composes downward togroup→semigroup,group→magma).Sig-CommutativeMonoidandSig-AbelianGroupreuseSig-MonoidandSig-Grouprespectively; the only addition iscommto the theory.
All equations come from the generic builders in Classical.Equations [M3-2]. Distinguished elements (the identity, the inverse) are nullary/unary operation symbols of the signature, per ADR-002 v2 §9.
Description¶
Follow the pattern established in [M3-3]/[M3-4] to add the monoid-and-group family, with corresponding signatures, theories, bundle views, and level-fixed veneers.
Tasks¶
-
Classical/Structures/Monoid.lagda.md. -
Classical/Structures/CommutativeMonoid.lagda.md. -
Classical/Structures/CommutativeSemigroup.lagda.md. -
Classical/Structures/Group.lagda.md. -
Classical/Structures/AbelianGroup.lagda.md. - Corresponding signatures, theories, bundles (per [M3-3]), Small veneers.
- Worked examples:
(ℕ, +, 0)as CommutativeMonoid;(ℤ, +, 0, -)as AbelianGroup.
Acceptance criteria¶
- All four structures type-check and round-trip through their bundles.
- Worked examples type-check.
Issue M3-7: Classical.Semilattice and Classical.Lattice (#264, closed)¶
Labels: milestone-3-classical
v2 amendment (2026-05-17)¶
Renumbered M3-5 → M3-7 following revision of ADR-002 v2.
Scope is unchanged. Conventions inherit from M3-2 / M3-3 / M3-4: hyphen-separated ∧-Op, ∨-Op constructors; Sig-Semilattice and Sig-Lattice signatures; equations composed from Associative, Commutative, Idempotent, Absorbs builders in Classical.Equations.
The "two binary ops" vs "one binary op with the other defined" representational question for Lattice — flagged in the original issue — is settled in favor of two binary operation symbols (∧-Op and ∨-Op), consistent with the signature-extension policy: each operation that participates in the variety's equations gets its own signature symbol.
Description¶
Lattices are centrally important because Con 𝑨 and Sub 𝑨 are naturally lattices, and the Finite Lattice Representation Problem (M6) is stated in terms of lattices.
Tasks¶
-
Classical/Signatures/Lattice.agda: two binary operations (∧,∨) or one (meet), depending on formulation. -
Classical/Theories/Lattice.agda: associativity, commutativity, idempotence, absorption. -
Classical/Structures/Semilattice.agda. -
Classical/Structures/Lattice.agda. - Bridge to
Algebra.Lattice.Bundles. - Prove equivalence of algebraic (meet-join) and order-theoretic formulations.
Acceptance criteria¶
- Both structures type-check.
- The meet-join / order-theoretic equivalence theorem is proved.
- Bridge to stdlib round-trips on
𝟚as a Boolean lattice.
Issue M3-8: Classical.Ring and Classical.CommutativeRing (#265, closed)¶
Labels: milestone-3-classical, help-wanted
v2 amendment (2026-05-17)¶
Renumbered M3-6 → M3-8 following this revision of the ADR-002 v2 document.
Scope is unchanged. Conventions inherit from M3-6 (Monoid/Group/AbelianGroup) and from M3-7 (the precedent for multiple binary operations in one signature).
Sig-Ring has signature symbols +-Op (binary), 0-Op (nullary, the additive identity), -Op (unary, the additive inverse), ·-Op (binary), 1-Op (nullary, the multiplicative identity). Th-Ring composes the abelian-group equations on (+-Op, 0-Op, -Op), the monoid equations on (·-Op, 1-Op), and the distributivity equations from DistributesOverˡ/DistributesOverʳ. Forgetful ring→abelianGroup (additive structure) and an additional forgetful ring→monoid (multiplicative structure) defined alongside the core.
Description¶
Rings depend on AbelianGroup for the additive structure, so this issue comes after M3-4.
Tasks¶
-
Classical/Signatures/Ring.agda. -
Classical/Theories/Ring.agda. -
Classical/Structures/Ring.agda. -
Classical/Structures/CommutativeRing.agda. - Bridge to stdlib.
- Worked example:
(ℤ, +, *, 0, 1, -)as CommutativeRing.
Acceptance criteria¶
- Both structures type-check.
- The worked example
ℤ-ringtype-checks. - Bridge to stdlib
CommutativeRinground-trips onℤ.
Issue M3-9: Expand Examples/ with worked classical-structure instances (#266, closed)¶
Labels: documentation, milestone-3-classical
v2 amendment (2026-05-17)¶
Renumbered M3-7 → M3-9 following revision of ADR-002 v2.
Scope is unchanged. Per-structure worked examples land with their structure issues (M3-3 ships ℕ-magma; M3-4 ships ℕ-semigroup; M3-6 ships ℕ-monoid and ℤ-group; etc.). This issue is therefore reduced to cross-structure and richer examples: free magmas, free semigroups, term-rewriting demonstrations, presentations, finite-quotient examples for use as Demos/ companion material, etc.
The reduction in scope reflects the M3-3-onward convention that one canonical worked example per structure ships with the structure itself; this issue exists for the additional examples that wouldn't fit cleanly in any one structure's file.
Description¶
The Examples/ directory is thin. Add worked examples that exercise the Classical/ layer.
Tasks¶
Update (20260531)¶
Missed ask. We forgot to address the following: "Richer examples: free magmas, free semigroups, term-rewriting demonstrations, presentations, finite-quotient examples for use as Demos/ companion material, etc." Let's reopen and add these in a new PR attached to this issue.
-
(ℕ, +, 0)as aCommutativeMonoid, with HSP specialized to it. -
(ℤ, +, 0, -)as anAbelianGroup. -
𝟚with two operations as aDistributiveLattice. - A small finite group (
ℤ/3ℤ) with its congruence lattice computed. - A finite Heyting algebra as a Lattice example.
- An example of a nonabelian group. (I believe the only example of the
Grouptype inExamples.Classicalis the integers. We should add an example of a nonabelian group that does not happen to be abelian as well.) - An example of a "commutative idempotent binar" (that is, a magma with an idempotent commutative binary operation); the operation should be defined by its Cayley table. (I'm not sure how to implement a Cayley table to describe an operation in Agda yet, so this task will be an excellent opportunity for us to figure out the best way to do that.)
Acceptance criteria¶
- At least five new example files in
Examples/Classical/. - Each example type-checks and is documented in a prose header.
Issue M3-10: Free lattices: lattice terms and Whitman's solution to the word problem (#589, closed)¶
Labels: milestone-3-classical
Description¶
The library has lattices (Classical.Structures.Lattice), their equational theory (Classical.Theories.Lattice), and the relatively free algebra 𝔽[ X ] of Setoid.Varieties.SoundAndComplete, whose carrier equality is derivable equality Th-Lattice ⊢ X ▹ s ≈ t. What it lacks is any way to compute in a free lattice: derivable equality is a relation, not a procedure. Whitman's 1941 solution to the word problem ([FJN], Theorem 1.11) is a structural recursion on a pair of terms that decides s ≤ t in FL(X), and so decides equality. This issue adds it, with soundness and completeness proved, so that FL(X) becomes a lattice the library can both reason about and evaluate in.
This is the first of four issues building a free-lattice layer (#590, #591, #592). Together they supply the tools that McNulty's free-lattice Nullstellensatz problem and Dean's problem (whether a free lattice has an ascending chain of sublattices isomorphic to FL(3)) both need, and that nothing in the library provides today.
Whitman's rules ([FJN], Theorem 1.11), for terms over a generator type X with decidable equality, are the following:
x ≤ yfor generatorsx,yiffx = y;s₁ ∨ s₂ ≤ tiffs₁ ≤ tands₂ ≤ t;s ≤ t₁ ∧ t₂iffs ≤ t₁ands ≤ t₂;x ≤ t₁ ∨ t₂, for a generatorx, iffx ≤ t₁orx ≤ t₂;s₁ ∧ s₂ ≤ y, for a generatory, iffs₁ ≤ yors₂ ≤ y;s₁ ∧ s₂ ≤ t₁ ∨ t₂iffs₁ ≤ t₁ ∨ t₂ors₂ ≤ t₁ ∨ t₂ors₁ ∧ s₂ ≤ t₁ors₁ ∧ s₂ ≤ t₂(this is Whitman's condition (W)).
The rules overlap (a join on the left and a meet on the right), so the procedure fixes a dispatch order: a join on the left is split first, then a meet on the right, and only then do the remaining four shapes apply. Every recursive call keeps one argument and replaces the other by a proper subterm, so the recursion is structural in the lexicographic sense Agda's termination checker accepts; no well-founded induction on rank is needed.
Two routes to correctness. [FJN] prove Theorem 1.11 through Day's doubling construction (Theorem 1.8). The direct syntactic route is shorter to mechanize and is the one recommended here: prove that the relation _≤ʷ_ the rules define is reflexive and transitive and that formal join and meet are its suprema and infima. The quotient of terms by s ≤ʷ t × t ≤ʷ s is then a lattice generated by X; every map X → L into a lattice extends to a homomorphism out of it (evaluation), and that extension respects _≤ʷ_ because each rule is valid in every lattice (soundness). Completeness of the rules, that ⟦ s ⟧ ≤ ⟦ t ⟧ in every lattice implies s ≤ʷ t, is then immediate by evaluating in the quotient itself. Transitivity is the one substantial proof: an induction on the triple (s, t, u) that case-splits on the shape of t, with two inversion lemmas (s₁ ∨ s₂ ≤ʷ t gives sᵢ ≤ʷ t; s ≤ʷ t₁ ∧ t₂ gives s ≤ʷ tᵢ, by induction on s) and two weakening lemmas (sᵢ ≤ʷ u gives s₁ ∧ s₂ ≤ʷ u, by induction on u, and dually s ≤ʷ tⱼ gives s ≤ʷ t₁ ∨ t₂, by induction on s).
Term representation. The algorithm, and the canonical forms of #590, want a dedicated inductive type of lattice terms (a generator, a binary meet, a binary join) with structural recursion on it. The library's generic Term X over Sig-Lattice has function-valued children (node ∧-Op (pair s t)), whose equality is the setoid _≐_ rather than _≡_; keep it as the bridge, not the workhorse. Translate in both directions and prove the round trips up to _≐_, so that the results here apply to Th-Lattice, to 𝔽[ X ], and to every Lattice of Classical.Structures.Lattice.
Tasks¶
- A module for lattice terms (
Classical.Structures.Lattice.Free.Term, or asdocs/STYLE_GUIDE.mddirects): the inductive type over a generator type with decidable equality, rank, evaluation in anyLattice α ρthroughLattice-Op, and the translation to and fromTerm XoverSig-Latticewith round-trip lemmas up to_≐_. -
Classical.Structures.Lattice.Free.Whitman: the decision procedure as aDec-valued structural recursion, or as a Boolean function with a reflection lemma; reflexivity, the inversion and weakening lemmas, transitivity; formal join and meet as supremum and infimum. -
FL X : Lattice _ _, the setoid quotient of terms by mutual_≤ʷ_, with the eight equations ofTh-Latticedischarged from the order (order first, as CLAUDE.md advises), and the generator mapX → FL X. - Soundness:
s ≤ʷ timplies⟦ s ⟧ η ≤ ⟦ t ⟧ ηin every lattice and every environmentη, for the order ofClassical.Properties.Lattice. - Completeness and the universal property: for a lattice
Landf : X → L, evaluationFL X → Lis the unique homomorphism extendingf; hences ≤ʷ tiff⟦ s ⟧ ≤ ⟦ t ⟧holds in every lattice. - The bridge to derivability:
Th-Lattice ⊢ X ▹ s ≈ tiffs ≤ʷ tandt ≤ʷ s, through the soundness and completeness theorems ofSetoid.Varieties.SoundAndComplete; so equality in𝔽[ X ]overTh-Latticeis decidable. - A worked example (
Examples.Classical.Lattices.FreeLattice3, or besideExamples.Setoid.FreeSemigroup): inFL (Fin 3), decide a handful of inequalities by evaluation, among them a failure of distributivity (x ∧ (y ∨ z) ≰ (x ∧ y) ∨ (x ∧ z)) and the two absorption identities. - Prose for every fence, as ADR-010 requires;
make gen-linksandmake corpus-statsfor the new modules;make checkfrom source.
Acceptance criteria¶
-
make checkpasses with the new modules; no postulate, noTERMINATINGpragma,--safethroughout. -
_≤ʷ_is decidable, sound, and complete for the order ofFL X, andFL Xis aLatticewith the universal property above, all as theorems with explicit types. - Derivable equality under
Th-Latticeis shown decidable through the bridge. - The example module decides the stated inequalities by evaluation and the verdicts are the expected ones.
- The field report on agda-mcp that CLAUDE.md asks for is filed.
References¶
- [FJN] R. Freese, J. Ježek, J. B. Nation, Free Lattices, Mathematical Surveys and Monographs 42, American Mathematical Society, 1995: Theorem 1.11 (Whitman's solution), Theorem 1.8 and Corollary 1.9 ((W) in free lattices and their sublattices), Chapter XI, Section 8 (the algorithms as a computer runs them).
- P. M. Whitman, "Free lattices", Annals of Mathematics 42 (1941) 325–330.
Issue M3-11: Free lattices: canonical form and canonical joinands (#590)¶
Labels: milestone-3-classical
Description¶
Whitman's procedure (#589) decides whether two terms name the same element of FL(X); it does not choose a name. [FJN], Theorem 1.17, does: every element of a free lattice has a term of minimal rank representing it, unique up to commutativity and associativity, called its canonical form, and Theorem 1.18 characterizes that form syntactically. A join t = t₁ ∨ ⋯ ∨ tₙ with n > 1 is in canonical form iff the following four conditions hold:
- each
tᵢis a generator or a formal meet; - each
tᵢis in canonical form; - the
tᵢform an antichain (tᵢ ≰ tⱼfori ≠ j); - if
tᵢ = ⋀ⱼ tᵢⱼthentᵢⱼ ≰ tfor everyj.
Dually for a meet, and a generator is always in canonical form. The elements the tᵢ represent are the canonical joinands of w, and Theorem 1.19 says they refine every join representation of w: if w = ⋁ uⱼ then every canonical joinand of w is below some uⱼ. Canonical joinands are the vocabulary of everything that follows this issue. Semidistributivity (#591) is three lines from Theorem 1.19, and the embedding lemma of #592 ([FJN], Lemma 9.13) is a statement about them.
Representation. Canonical form needs flattened, n-ary joins and meets: a canonical term is a generator, or a nonempty list of canonical meets-or-generators under a join, or dually. "Unique up to commutativity" is then a permutation of the list. Two formalizations are reasonable: a CanonicalTerm type with list-valued children and uniqueness stated up to Data.List.Relation.Binary.Permutation; or the same type with children sorted by a decidable total order on terms, which turns uniqueness into _≡_. Start with the first; the second is a refinement for a later consumer that needs decidable _≡_ on normal forms.
The algorithm. Canonicalize bottom-up. For a join, canonicalize the two children, flatten any child that is itself a join, delete every joinand that lies below another joinand, and while some meet-joinand tᵢ = ⋀ⱼ tᵢⱼ has a tᵢⱼ ≤ t, replace tᵢ by that tᵢⱼ (which is already canonical, being a subterm) and repeat; dually for a meet. Each replacement lowers the rank, which is the termination measure for that loop: a well-founded recursion on rank, or a fuel argument with a proof that the fuel suffices. [FJN], Chapter XI, Section 8, presents the procedure as a computer runs it.
Tasks¶
-
Classical.Structures.Lattice.Free.Canonical: the canonical-term type, its embedding⌊_⌋back into the lattice terms of #589, andIsCanonicalas the four conditions of [FJN], Theorem 1.18, stated with the decidable order_≤ʷ_. -
canonical : LatTerm X → CanonicalTerm Xwith⌊ canonical t ⌋equal totinFL XandIsCanonical (canonical t). - Uniqueness ([FJN], Theorem 1.17, reached through Theorem 1.18): two canonical terms representing the same element are equal up to permutation of joinands and meetands, by the argument of Lemma 1.16 and induction. Minimality of rank itself is a stretch goal.
-
canonicalJoinands : LatTerm X → List (LatTerm X)andcanonicalMeetands, with Theorem 1.19: ifw = ⋁ uⱼinFL Xthen every canonical joinand ofwis below someuⱼ. As a stretch goal, Theorem 1.20: a join-irreducibleuis a canonical joinand ofwiffw = u ∨ afor someawithw > v ∨ afor everyv < u. - Decidable equality of elements of
FL Xby comparison of canonical forms, and its agreement with the decision of #589. - Worked examples in the example module of #589: canonical forms of a few terms over three generators, among them one where the fourth condition of Theorem 1.18 fires.
- Prose for every fence;
make gen-linksandmake corpus-stats;make checkfrom source.
Acceptance criteria¶
-
canonicalis total and--safe, withoutTERMINATING; its soundness and theIsCanonicalproperty are theorems. - Uniqueness up to permutation is a theorem.
- Theorem 1.19 is a theorem, stated for the canonical joinands the function computes.
- The examples check, and the field report on agda-mcp is filed.
References¶
- [FJN] R. Freese, J. Ježek, J. B. Nation, Free Lattices, Mathematical Surveys and Monographs 42, American Mathematical Society, 1995: Chapter I, Section 3 (Lemma 1.16, Theorems 1.17 to 1.20); Chapter XI, Section 8.
Issue M3-12: Semidistributivity and Whitman's condition: predicates, free lattices, finite decision, and the examples M₃ and N₅ (#591)¶
Labels: milestone-3-classical
Description¶
A lattice is join semidistributive (SD∨) if a ∨ b = a ∨ c implies a ∨ b = a ∨ (b ∧ c), meet semidistributive (SD∧) dually, and semidistributive if both. It satisfies Whitman's condition (W) if s₁ ∧ s₂ ≤ t₁ ∨ t₂ implies s₁ ≤ t₁ ∨ t₂ or s₂ ≤ t₁ ∨ t₂ or s₁ ∧ s₂ ≤ t₁ or s₁ ∧ s₂ ≤ t₂. All three are universal Horn sentences, so sublattices inherit them. Free lattices satisfy all three: (W) is [FJN], Theorem 1.8 (in the development of #589 it is the sixth rule, read through the supremum and infimum characterizations), and semidistributivity is the Jónsson–Kiefer theorem, [FJN], Theorem 1.21, whose proof is three lines from Theorem 1.19 of #590. Conversely, Nation's theorem ([FJN], Theorem 5.55) says that a finite lattice is a sublattice of a free lattice iff it is semidistributive and satisfies (W). Nation's theorem is deep and is not to be formalized here. What this issue delivers is everything around it: the predicates, the theorem that free lattices (hence their sublattices) satisfy them, decision procedures for them on finite lattices, and two worked examples that separate the conditions.
The two examples are the following:
M₃, the five-element modular nondistributive lattice with atomsa,b,c: it satisfies (W), since its only proper meets are0, which lies below everything, and a comparable pair meets to one of its members; but it fails SD∨ (a ∨ b = 1 = a ∨ c, yeta ∨ (b ∧ c) = a) and, dually, SD∧.N₅, the pentagon (0 < a < c < 1and0 < b < 1): it satisfies SD∨, SD∧, and (W), so by Nation's theorem it is a sublattice of a free lattice.
A table-driven constructor for finite lattices on Fin n, with the eight lattice equations discharged by exhaustive decision (from-yes over all?, as Examples.Classical.Lattices.L3Heyting and the Cayley-table groups of Examples.Classical.Groups already do), makes each example a pair of tables and keeps the examples cheap. At five elements each equation is at most 125 cases.
Tasks¶
-
Classical.Properties.Lattice.Semidistributive(or a namedocs/STYLE_GUIDE.mdprefers):IsJoinSemidistributive,IsMeetSemidistributive,IsSemidistributive, andSatisfiesWoverLattice α ρ, stated with the order ofClassical.Properties.Lattice; preservation under sublattices and under lattice isomorphism. - For
FL Xof #589:SatisfiesW (FL X)([FJN], Theorem 1.8 and Corollary 1.9) and, from the canonical joinands of #590,IsSemidistributive (FL X)([FJN], Theorem 1.21). Record in prose that the equivalent form (3) of SD∨ in [FJN], Theorem 1.21, is not needed for the free-lattice case. - Decision procedures: for a lattice whose carrier is a
FiniteAlgebra(Setoid.Algebras.Finite),isJoinSemidistributive?,isMeetSemidistributive?, andsatisfiesW?asDecvalues, by enumeration of triples and quadruples. - A table-driven finite lattice constructor on
Fin n(Classical.Structures.Lattice.Table, afterClassical.Structures.Group.TableGroup), the lattice laws decided exhaustively. -
Examples.Classical.Lattices.M3andExamples.Classical.Lattices.N5as tables, with the decision procedures evaluated to the verdicts above, and the module list ofExamples.Classical.Latticesextended. - Prose for every fence;
make gen-linksandmake corpus-stats;make checkfrom source.
Acceptance criteria¶
- The four predicates and their preservation lemmas type-check with explicit types.
-
FL Xis proved to satisfy (W) and both semidistributive laws. - On
M₃the procedures return "satisfies (W)", "fails SD∨", and "fails SD∧"; onN₅all three return "satisfies"; each by evaluation, not by a hand proof. - The field report on agda-mcp is filed.
References¶
- [FJN] R. Freese, J. Ježek, J. B. Nation, Free Lattices, Mathematical Surveys and Monographs 42, American Mathematical Society, 1995: Theorem 1.8, Corollary 1.9, Theorem 1.21 (Jónsson and Kiefer), Theorem 5.55 (Nation).
- B. Jónsson and J. E. Kiefer, "Finite sublattices of a free lattice", Canadian Journal of Mathematics 14 (1962) 487–497.
- J. B. Nation, "Finite sublattices of a free lattice", Transactions of the American Mathematical Society 269 (1982) 311–337.
Issue M3-13: Free lattices: substitutions, endomorphisms, free generating sets, and embeddings (#592)¶
Labels: milestone-3-classical
Description¶
The problems this layer is built for are statements about maps between free lattices. McNulty's free-lattice Nullstellensatz problem asks, for a congruence θ of FL(n), which equations hold under every solution of θ, where a solution is an n-tuple of elements of FL(n), that is, an endomorphism of FL(n); the answer is the intersection of the kernels of the endomorphisms whose kernel contains θ. Dean's problem asks whether a free lattice has an infinite strictly ascending chain of sublattices each isomorphic to FL(3); the known partial results (Freese's 1997 notes) rest on [FJN], Corollary 1.13, which decides when a finite subset of a free lattice generates a free sublattice freely, and on [FJN], Lemma 9.13, which says that a lattice embedding σ : FL(X) ↣ FL(Y) sends every canonical joinand of w that is not a generator to a canonical joinand of σ(w). This issue supplies those tools on top of #589, #590, and #591.
Corollary 1.13: a subset S of a free lattice generates a sublattice isomorphic to a free lattice, freely generated by S, iff for every s ∈ S and every finite Y ⊆ S, s ≤ ⋁ Y implies s ∈ Y, and dually. For finite S the condition quantifies over finitely many Y, and each instance is one Whitman decision, so the criterion is decidable. Its proof goes through Corollary 1.12 (a lattice that satisfies (W) and is generated by a set X on which the join and meet conditions hold is isomorphic to FL(X)) and Theorem 1.11.
The first Nullstellensatz datum falls out of #591. The pair (x ∧ y, x ∧ (y ∨ z)) lies in the closure of the congruence generated by (x ∧ y, x ∧ z), because every solution of x ∧ y ≈ x ∧ z satisfies x ∧ y ≈ x ∧ (y ∨ z) by SD∧ in FL(3). It does not lie in that congruence, because the homomorphism FL(3) → M₃ sending the generators to the three atoms identifies x ∧ y with x ∧ z (both go to 0) and separates x ∧ y from x ∧ (y ∨ z) (0 and a). So the closure operator of the problem is strictly larger than congruence generation, and the two semidistributive laws are its first entries.
Tasks¶
-
Classical.Structures.Lattice.Free.Substitution: substitutionsX → LatTerm Y, their action on terms, and the induced homomorphismFL X → FL Y; the evaluation lemma (evaluatingtunder⟦_⟧ ∘ σequals evaluatingt [ σ ]), asSetoid.Varieties.SoundAndCompletestates it for𝔽[ X ]; endomorphisms ofFL Xas the caseY = X; and the theorem that every homomorphismFL X → FL Yis the one induced by its restriction to the generators. - Kernels: the kernel of an induced homomorphism as a congruence of
FL X(throughSetoid.HomomorphismsandSetoid.Congruences), andsolves? : Sub X Y → List (LatTerm X × LatTerm X) → Dec _, deciding whether a substitution's kernel contains a finite list of pairs. - The closure of a finite list of pairs under all solutions, as a predicate; a refutation certificate (a substitution that solves
Σand nots ≈ t) with its checker; and theM₃example above as a theorem:(x ∧ y, x ∧ (y ∨ z))is in the closure of(x ∧ y, x ∧ z)and not in the congruence it generates. - Free generating sets:
FreelyGenerates Sas the condition of Corollary 1.13,freelyGenerates? : (S : List (LatTerm X)) → Dec (FreelyGenerates S), and the theorem that the condition is sufficient (the sublattice generated bySis isomorphic toFL S, through Corollary 1.12 and Theorem 1.11); necessity is a stretch goal. - [FJN], Lemma 9.13, for embeddings
FL X ↣ FL Y(injective homomorphisms): a canonical joinand ofwthat is not a generator is sent to a canonical joinand ofσ w; and the consequence Freese's notes use, that the term expressingwin the images of the generators is a truncation of the canonical form ofw. - A worked example: Freese's one-step example from "Notes on Dean's problem", two triples
{a, b, c}and{a', b', c'}in the free lattice on nine generators, each freely generating, with⟨a, b, c⟩properly contained in⟨a', b', c'⟩, checked byfreelyGenerates?and by Whitman's procedure. Measure the cost of the decisions on terms of that size before committing to it; [FJN], Chapter XI, Section 8, has the polynomial-time formulation if the naive recursion is too slow. As a further stretch goal, [FJN], Theorem 1.28 (FL(ω)embeds inFL(3)) for the first few of Whitman's elements. - Prose for every fence;
make gen-linksandmake corpus-stats;make checkfrom source.
Acceptance criteria¶
- Substitution, the induced homomorphism, the evaluation lemma, and the characterization of homomorphisms between free lattices by their values on generators are theorems.
- The
M₃closure example is a theorem. -
freelyGenerates?is a decision procedure whose positive answers are proved sufficient. - Lemma 9.13 is a theorem.
- The field report on agda-mcp is filed.
References¶
- [FJN] R. Freese, J. Ježek, J. B. Nation, Free Lattices, Mathematical Surveys and Monographs 42, American Mathematical Society, 1995: Theorem 1.11, Corollaries 1.12 and 1.13, Theorem 1.28, Lemma 9.13, Chapter XI, Section 8.
- R. Freese, "Notes on Dean's problem", 1997, https://math.hawaii.edu/~ralph/Notes/DeansProb/dean.pdf.
- G. F. McNulty, "A juggler's dozen of easy problems", Algebra Universalis 74 (2015) 17–34, the section "The Free Lattice Nullstellen Problem".
Milestone 3 Dependencies¶
The pattern-setters are M3-2 (infrastructure), M3-3 (no-equation pattern), M3-4 (one-equation pattern) — the design choices made there propagate to every other structure. M3-6 (Monoid/Group) and M3-7 (Lattice) are the mid-level hubs; M3-8 (Ring) needs M3-6 because rings are abelian groups with extra structure, and M3-9 (Examples) aggregates from several of the structure issues.
graph TD
M2_1["M2-1: Freeze Base"]:::ext
M2_6["M2-6: Extract Setoid foundations"]:::ext
M3_1["M3-1: Classical/ scaffold"]
M3_2["M3-2: Operations + Equations infra"]
M3_3["M3-3: Magma (no-equation pattern)"]
M3_4["M3-4: Semigroup (one-equation pattern)"]
M3_5["M3-5: Stdlib bridges (continued)"]
M3_6["M3-6: Monoid / Group"]
M3_7["M3-7: Lattice"]
M3_8["M3-8: Ring"]
M3_9["M3-9: Examples"]
M2_1 --> M3_1
M2_6 --> M3_1
M3_1 --> M3_2
M3_2 --> M3_3
M3_3 --> M3_4
M3_4 --> M3_5
M3_4 --> M3_6
M3_5 --> M3_7
M3_6 --> M3_7
M3_6 --> M3_8
M3_4 --> M3_9
M3_6 --> M3_9
M3_7 --> M3_9
classDef ext fill:#f0f0f0,stroke:#999,stroke-dasharray: 4 3,color:#555
---¶
Milestone 4 — Style and naming uniformity sweep¶
Issue M4-1: Mechanical style & notation sweep (umbrella) (#267, closed)¶
Labels: documentation, milestone-4-style
Description¶
Umbrella for the mechanical half of Milestone 4: bring the live trees (Overture/, Setoid/, Classical/, Demos/, Examples/) into docs/STYLE_GUIDE.md conformance for everything that changes compiled code — notation and imports — and reconcile the guide with itself. All prose work (rich module headers, per-definition docstrings, anchor removal) is tracked under M4-2 (#268) and its per-subtree children.
The naming audit is already discharged. grep -rnE 'is-homomorphism|\bHom\b' src/Setoid/ is empty; the only is-hom/is-epi hits are descriptive lemma names (⊙-is-hom, lift-of-epi-is-epi, hom𝔽[_]-is-epic), not synonyms of the IsHom/IsEpi predicates. The Setoid public API is already on IsHom/hom, IsMon/mon, IsEpi/epi. What remains is notation, imports, and the guide.
Children¶
-
367¶
-
368¶
-
369¶
-
370¶
-
372¶
-
384 —
fst/snd→proj₁/proj₂, split out of #367 task 4 (the rename turned out to be a deliberate library-wide convention across ~17 modules, not a dead rename).¶
Residual import hygiene rides along with #368/#369 (which rewrite every import block touching projections/interpretation) and the M4-2 per-subtree PRs; no separate issue.
Exit criterion¶
- All sub-issues closed.
-
make checkpasses;EverythingLegacy.agdastill compiles (warnings fromLegacy/expected). -
grep -rE 'is-homomorphism|\bHom\b' src/Setoid/ src/Classical/is empty. - The Projections and Interpretation tables in
docs/STYLE_GUIDE.mdmatch the live trees.
Issue M4-1a: Migrate ∣_∣ / ∥_∥ → proj₁ / proj₂ (#367, closed)¶
Labels:
Description¶
Remove the bracket projections from the live trees. Generic Σ-projections become stdlib proj₁ / proj₂; signature components become the existing OperationSymbolsOf / ArityOf from Overture.Signatures (already canonical in Classical/). The ∣_∣ / ∥_∥ definitions stay in Overture.Basic with WARNING_ON_USAGE so Legacy/Base/ still compiles. Mechanical but verified by recompilation — execute in Claude Code.
Tasks¶
-
Overture.Basic: decouple∥_∥'s type from∣_∣; addWARNING_ON_USAGEto both. -
Overture.Signatures: rewriteOperationSymbolsOf/ArityOfto useproj₁/proj₂; drop theOverture.Basicbracket import; fix the staleBase.Functionsreference and the per-tree prose. - Sweep all non-
Legacy/callsites:∣ 𝑆 ∣→OperationSymbolsOf 𝑆,∥ 𝑆 ∥→ArityOf 𝑆, all other∣ e ∣/∥ e ∥→proj₁ e/proj₂ e(code fences and inline prose). - Per-file import surgery; collapse the dead
proj₁ to fst ; proj₂ to sndrename inSetoid/Homomorphisms/Properties. - Amend ADR-002 §1 (the unified policy) — or fold into #CCC.
-
make check.
Acceptance criteria¶
-
rg '∣' src --glob '!src/Legacy/**'matches only the∣_∣/∥_∥definitions inOverture.Basic. -
make checkpasses;Legacy/compiles.
Issue M4-1b: Complete the _̂_ → _^_ migration (#368, closed)¶
Labels:
Description¶
_̂_ was deprecated in v3.0 in favour of the ASCII _^_, with a WARNING_ON_USAGE pragma already at the definition site in Setoid.Algebras.Basic (ADR-002 §7). The callsite migration is partial: Setoid.Algebras.Products is on _^_, but Setoid.Algebras.Congruences still imports and uses _̂_ and trips the warning. Finish it across the live trees.
Tasks¶
- Rewrite every non-
Legacy/_̂_callsite and import to_^_(code fences and inline prose). - Update the
### Interpretationtable indocs/STYLE_GUIDE.md(folds into #CCC if landing together). -
make checkwith no_̂_deprecation warnings outsideLegacy/.
Acceptance criteria¶
-
grep -rn '̂' src/ | grep -v src/Legacy/matches only the_̂_definition/deprecation inSetoid.Algebras.Basicand insrc/Demos/HSP.lagda.md; (the latter is frozen for historical continuity since it's cited in the Birkhoff HSP paper). -
make checkpasses.
Issue M4-1c: Reconcile docs/STYLE_GUIDE.md self-contradictions (#369, closed)¶
Labels:
Description¶
The guide contradicts itself in three places; its own meta-rule makes each an M4-1 bug.
+ Docstring form: the "prose comment block" example uses -- | inside a fence, which "Prose belongs in Markdown" forbids. Rewrite to Markdown-prose-before-fence.
+ Hom vs hom: the same example defines a capital Hom, the synonym the Naming section deprecates. Use lowercase hom.
+ Tables: update Projections to reflect #367 and Interpretation to reflect #368.
Tasks¶
- Apply the three edits (drafted in the PR thread).
- Verify no remaining
-- |-style docstring examples in the guide. - Amend ADR-002 §1 and
Overture.Signaturesprose to the unified projection policy; fix the staleBase.Functionscross-reference.
Acceptance criteria¶
- The guide's examples use lowercase
hom,_^_, and Markdown-prose docstrings. - Projections and Interpretation tables match the post-migration trees.
Issue M4-1d: Repo-wide style-guide violation audit (#370, closed)¶
Labels:
Description¶
A scripted sweep of the live trees for STYLE_GUIDE.md violations, producing a checklist that feeds the migration PRs and the M4-2 per-subtree PRs. Run in Claude Code.
Tasks¶
- Notation: residual
∣_∣/∥_∥/_̂_outsideLegacy/. - Imports: bare
open importwithoutusing; cosmeticrenaming; non-alphabetical groups. - Headers: modules whose header is only YAML + the one-line "This is the … module" (feeds M4-2).
- Anchors:
<a id=…>occurrences (feeds M4-1g; ≈ 90 acrossSetoid/). - Naming: any
is-xpredicate forms or synonym pairs (expected: none inSetoid/). - Emit
docs/audits/M4-style-audit.mdwith per-file findings.
Acceptance criteria¶
- Audit committed; every finding fixed or linked to a child PR.
Issue M4-1e: Normalize code-fence whitespace (#372, closed)¶
Labels:
Description¶
The .lagda→.lagda.md migration script left blank lines between the ```agda opener and the first line of code in many blocks. Collapse them so the first code line is adjacent. Live trees only; Legacy/ stays frozen. Pure whitespace, semantically null for both Agda and Markdown.
Tasks¶
-
perl -0pi -e 's/```agda\n\n+/```agda\n/g'acrosssrc/excludingsrc/Legacy/. -
make check.
Acceptance criteria¶
-
rg -U '```agda\n\n' src --glob '!src/Legacy/**'is empty.
Issue M4-1f: Unify fst / snd → proj₁ / proj₂ (#384, closed)¶
Labels:
Description¶
Split out of #367 task 4. That task asked to "collapse the dead proj₁ to fst ; proj₂ to snd rename in Setoid.Homomorphisms.Properties", but the rename is not dead: fst / snd is a deliberate short-hand for proj₁ / proj₂ used across ~17 live modules. Unifying it on the canonical proj₁ / proj₂ (per the STYLE_GUIDE "one canonical form per concept" rule) is therefore its own mechanical sweep, separate from the bracket-projection migration (#367), which is now complete.
Scope¶
The renaming ( proj₁ to fst ; proj₂ to snd ) idiom (or a one-sided variant) appears in:
Overture/Relations,Overture/Functions,Overture/Adjunction/Galois;Setoid/Functions/{Inverses, Surjective};Setoid/Homomorphisms/{HomomorphicImages, Noether, Properties, Factor};Setoid/Subalgebras/{Properties, Subalgebras};Setoid/Varieties/{FreeAlgebras, SoundAndComplete, Preservation, HSP, EquationalLogic}.
Demos/HSP also uses it; consistent with the #367 / #368 decisions, the self-contained demo is exempt by default.
Tasks¶
- Drop the
proj₁ to fst/proj₂ to sndrenames from eachData.Productimport. After #367,proj₁/proj₂are re-exported by theOvertureumbrella, so most modules can drop theData.Productprojection import entirely rather than re-add a plain one. - Rewrite
fst→proj₁andsnd→proj₂at every callsite. - Gotcha: identifiers such as
Lift-hom-fst/Lift-hom-snd(definition names inSetoid.Homomorphisms.Properties) and any other…fst/…snd-suffixed names must not be rewritten. A blinds/\bfst\b/proj₁/corrupts them, since\bmatches inside a hyphenated name. -
make check.
Acceptance criteria¶
-
grep -rn 'proj₁ to fst\|proj₂ to snd' srcmatches onlysrc/Legacy/**(andsrc/Demos/HSP.lagda.mdif exempted). -
make checkpasses;Legacy/compiles.
Part of the M4-1 umbrella (#267).
Issue M4-1g: Remove HTML heading anchors (rely on kramdown auto-slugs) (#387, closed)¶
Labels:
Description¶
Split out of the M4 style audit (docs/audits/M4-style-audit.md, finding 4). The docs/STYLE_GUIDE.md § Section headings rule says headings should be plain ATX, not wrapped in <a id="…">…</a>; the renderer (Jekyll + kramdown) auto-generates a slug id from each heading. The audit found ~300 such anchors across 111 files. Pursue per-subtree, starting with Setoid/ (~93 anchors / 43 files).
Algorithm (per anchor <level> <a id="TAG">TEXT</a>)¶
- Compute
slug = kramdown_generate_id(TEXT). - If
slug == TAG: drop the wrapper →<level> TEXT(the auto-slug reproduces the same id, so any#TAGlink still resolves). - If
slug ≠ TAG: check whetherTAGis used as a cross-reference (#TAGin a link, anywhere insrc/+docs/). - If not referenced: drop the wrapper →
<level> TEXT. - If referenced: keep the id explicitly via the kramdown attribute-list form →
<level> TEXT {#TAG}.
This guarantees no cross-reference breaks while removing the HTML wrappers.
Notes¶
- Cross-references are scanned repo-wide (a
Setoid/anchor can be linked fromOverture/, the paper, etc. — e.g.proof-of-the-hsp-theoremis linked fromOverture.Preface). src/Legacy/**is frozen and excluded from rewriting (but still scanned for references).- Anchor changes are pure prose (outside
agdafences);make checkis unaffected but is run as the gate.
Acceptance criteria¶
-
rg -n '<a id=' src/Setoidis empty (after theSetoid/PR; further subtrees follow). - No cross-reference
#TAGis left dangling. -
make checkpasses.
Part of Milestone 4 (style and naming uniformity sweep); see also the umbrella #267 and the audit #370.
Issue M4-2: Docstring pass for all user-facing definitions (#268, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Description¶
Every record, type family, and top-level function in the public API should have a prose comment block explaining what it is, when to use it, and cross-references to related definitions. Long-tail task; pursued as the per-subtree sub-issues below.
Where it stands¶
Measured by make docstrings (#537) over the live trees: 3226 public definitions in 307 modules, of which 201 sit under a fence carrying no real prose, and 50 modules open with nothing beyond the boilerplate "This is the [X][] module of the …" sentence.
make docstrings is a ratchet pinned at DOCSTRING_MAX_GAPS (201) and DOCSTRING_MAX_WEAK_HEADERS (50), so both counts can only fall. The policy and its reasoning are recorded in ADR-010. Each sub-issue lowers it.
Tasks¶
- #539 — Setoid/Algebras and Setoid/Homomorphisms (25 gaps, 10 headers)
- #540 — Setoid/Subalgebras (23, 5)
- #541 — Setoid/Varieties, Congruences, Terms, Categories (11, 9)
- #542 — Setoid/Functions, Setoid/Relations, Setoid barrels (6, 5)
- #543 — Classical/Structures, root and Lattice (34, 1)
- #544 — Classical/Structures/Group (31, 1)
- #545 — Classical/Bundles, Signatures, rest of Classical (37, 1)
- #546 — Examples (30, 8)
- #547 — Overture, FLRP, Exercises, top-level barrels (4, 10)
Done: #537 (the audit tool, the baseline, the CI ratchet) · #538 (exemplar: Setoid.Algebras.Basic) · #387 (the <a id> anchor sweep).
Acceptance criteria¶
-
make docstringsreports 0 definitions without a prose block, withDOCSTRING_MAX_GAPSat 0. - No module opens with only the boilerplate sentence.
The original criterion said a "grep-based audit". A grep cannot do this — the corpus has no -- | docstrings, prose lives in Markdown outside the fences, and almost every definition is indented inside an anonymous module _ … where. scripts/python/docstring_audit.py parses literate structure and Agda's layout rule instead; it is validated against Agda's own scope checker.
The bar (decided)¶
Settled in ADR-010, and reflected in docs/STYLE_GUIDE.md:
- The bar is per code fence. Every fence is preceded by a real paragraph, and every module opens with prose beyond the boilerplate sentence. 201 definitions and 50 module headers to clear;
make docstringsenforces both, ratcheted. - One definition per fence is rejected as a repository-wide rule. It would enforce layout rather than content — 1952 paragraphs each restating a type signature would satisfy it — and it fragments pages that are meant to read as an exposition of universal algebra.
--strictstays in the tool as a diagnostic for sizing, never as a gate. - A block covering several definitions should name each of them, so a reader, and the corpus extractor of #275, can tell which sentence belongs to which definition. Reported as the
namedcolumn (19% today); tracked, deliberately not gated.
Conventions for a docstring PR¶
Every sub-issue follows these; they are recorded once here rather than repeated nine times.
- The rule is
docs/STYLE_GUIDE.md§ "Every public definition has a prose comment block" and § "Module headers have comment blocks". Prose is Markdown before the code fence, never-- |inside it. A comment that only restates the type signature fails the bar. - The tool:
make docstrings-listnames every gap;python3 scripts/python/docstring_audit.py <path> --list --exit-zeroscopes it to a subtree;--strictshows the other reading. - The exemplar is #538. Copy its shape: what the definition is mathematically, when a reader reaches for it, two or three cross-references.
- Module headers: keep the
This is the [X][] module of the …line and add paragraphs after it, asSetoid.Terms.MonadandClassical.Structures.Lattice.OrdinalSumdo. - Ground the prose or mark it TODO. Write only what is supported by the definition itself, by prose the library already contains, or by a source actually read. Where the mathematics needs the author, leave
<!-- TODO(#268): … -->saying what would be needed. In the PR, name the paragraphs that are the agent's and the ones it is least sure of. A short list of "I could not write this one, and here is why" is a better deliverable than plausible-sounding filler. - Cross-references are reference-style (
[Setoid.Algebras.Products][]); the label must already exist indocs/_links.mdormake check-linksfails. - Style:
+bullets, two spaces after a sentence-ending period, one paragraph per source line, kramdown attribute spans for Agda names. Do not reflow pre-existing wrapped paragraphs. - Verify, do not assert: the Agda extracted from the fences must be byte-identical to
masterfor every file touched; type-check each modified module;make check-linksandmake docstringsgreen. If a prose edit changes compiled code, something is wrong. - Out of scope:
src/Legacy/**, any change to Agda code, reformatting, and editingdocs/STYLE_GUIDE.md.
Issue M4-2a: Docstrings: Setoid/Algebras and Setoid/Homomorphisms (#539, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Setoid/Algebras/ src/Setoid/Homomorphisms/
The heart of the Setoid tree and the first thing a new reader meets. Setoid.Algebras.Basic is already done by #538 and is the pattern to follow.
| measure | count |
|---|---|
| modules | 14 |
| public definitions | 116 |
| definitions with no prose on their fence | 25 |
| modules with a boilerplate-only or heading-only header | 10 |
Sized for one PR.
Done when¶
python3 scripts/python/docstring_audit.py src/Setoid/Algebras/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (73) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-2b: Docstrings: Setoid/Subalgebras (#540, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Setoid/Subalgebras/
Self-contained and gap-dense: subuniverses, generation, subdirect products. A good second subtree, once the convention from #538 has settled.
| measure | count |
|---|---|
| modules | 10 |
| public definitions | 144 |
| definitions with no prose on their fence | 23 |
| modules with a boilerplate-only or heading-only header | 5 |
Sized for one PR.
Done when¶
python3 scripts/python/docstring_audit.py src/Setoid/Subalgebras/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (99) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-2c: Docstrings: Setoid/Varieties, Congruences, Terms, Categories (#541, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Setoid/Varieties/ src/Setoid/Congruences/ src/Setoid/Terms/ src/Setoid/Categories/
Few gaps for their size, because the HSP-adjacent modules already carry good prose. Mostly header work plus a scattering of undocumented fences. Examples/Demos/HSP.lagda.md is a rich source of grounded prose for the Varieties material.
| measure | count |
|---|---|
| modules | 53 |
| public definitions | 632 |
| definitions with no prose on their fence | 11 |
| modules with a boilerplate-only or heading-only header | 9 |
Sized for one PR.
Done when¶
python3 scripts/python/docstring_audit.py src/Setoid/Varieties/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (370) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-2d: Docstrings: Setoid/Functions, Setoid/Relations, and the Setoid barrels (#542, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Setoid/Functions/ src/Setoid/Relations/ src/Setoid.lagda.md
Small, and mostly header work. The barrel modules hold no definitions but several open with boilerplate; a barrel's header is the natural place to say what the theme is and which submodule to reach for.
| measure | count |
|---|---|
| modules | 20 |
| public definitions | 104 |
| definitions with no prose on their fence | 6 |
| modules with a boilerplate-only or heading-only header | 5 |
Sized for one PR.
Done when¶
python3 scripts/python/docstring_audit.py src/Setoid/Functions/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (66) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-2e: Docstrings: Classical/Structures (root and Lattice) (#543, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Classical/Structures/ (excluding Group/, which is #544)
The quintuple pattern (ADR-002) makes these highly repetitive, so one well-written structure can be adapted across the rest. Do that deliberately: adapt, do not paste.
| measure | count |
|---|---|
| modules | 19 |
| public definitions | 336 |
| definitions with no prose on their fence | 34 |
| modules with a boilerplate-only or heading-only header | 1 |
Sized for one or two PRs; split by directory if the diff runs long.
Done when¶
python3 scripts/python/docstring_audit.py src/Classical/Structures/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (240) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-2f: Docstrings: Classical/Structures/Group (#544, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Classical/Structures/Group/
Split from the rest of Classical/Structures purely on size. The group-theoretic material feeds the FLRP research track, so cross-references into FLRP/ are worth getting right.
| measure | count |
|---|---|
| modules | 20 |
| public definitions | 310 |
| definitions with no prose on their fence | 31 |
| modules with a boilerplate-only or heading-only header | 1 |
Sized for one or two PRs; split by directory if the diff runs long.
Done when¶
python3 scripts/python/docstring_audit.py src/Classical/Structures/Group/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (202) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-2g: Docstrings: Classical/Bundles, Signatures, and the rest of Classical (#545, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Classical/Bundles/ src/Classical/Signatures/ src/Classical/Theories/ src/Classical/Small/ src/Classical/Categories/ src/Classical/Properties/ src/Classical/Interpretations/ src/Classical.lagda.md
Gap-dense but shallow. Each bundle module is a stdlib-interop view and wants a short paragraph naming the Algebra.Bundles record it matches and why the view exists. Classical/Categories/ is the exception — the categorical framing needs real intent, so mark it TODO rather than guessing.
| measure | count |
|---|---|
| modules | 57 |
| public definitions | 242 |
| definitions with no prose on their fence | 37 |
| modules with a boilerplate-only or heading-only header | 1 |
Sized for one or two PRs; split by directory if the diff runs long.
Done when¶
python3 scripts/python/docstring_audit.py src/Classical/Bundles/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (154) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-2h: Docstrings: Examples (#546, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Examples/
Demonstration modules. Prose should say what the example demonstrates and which theorem or definition it exercises, not re-describe the construction. Examples/Demos/HSP.lagda.md is the frozen TYPES 2021 artifact — leave its prose and its <a id> anchors alone (see #387).
| measure | count |
|---|---|
| modules | 41 |
| public definitions | 442 |
| definitions with no prose on their fence | 30 |
| modules with a boilerplate-only or heading-only header | 8 |
Sized for one or two PRs; split by directory if the diff runs long.
Done when¶
python3 scripts/python/docstring_audit.py src/Examples/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (272) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-2i: Docstrings: Overture, FLRP, Exercises, and the top-level barrels (#547, closed)¶
Labels: documentation, milestone-4-style, help-wanted
Scope¶
src/Overture/ src/FLRP/ src/Exercises/ src/agda-algebras.lagda.md
Only 4 gaps but 10 weak headers, so almost entirely module-header work. FLRP/ needs William's research context — the parachute, Kurzweil–Netter and Snow material encodes a live research programme that cannot be reconstructed from the types. Prefer deferring the FLRP headers to a follow-up over guessing.
| measure | count |
|---|---|
| modules | 73 |
| public definitions | 900 |
| definitions with no prose on their fence | 4 |
| modules with a boilerplate-only or heading-only header | 10 |
Sized for one PR.
Done when¶
python3 scripts/python/docstring_audit.py src/Overture/ --exit-zeroreports 0 gaps in scope.- Every module in scope opens with prose beyond the boilerplate sentence.
DOCSTRING_MAX_GAPSin theMakefileis lowered by the number cleared.
How¶
Conventions, tooling, grounding discipline and the verification checklist are in #268 — read that first; they are not repeated here. Exemplar: #538.
The bar is per code fence, settled in ADR-010: every fence carries a real paragraph, and every module opens with more than the boilerplate sentence. One definition per fence was considered and rejected, so the
--strictfigure for this subtree (476) sizes a road not taken and is not a backlog.
Sub-issue of #268. Tooling: #537.
Issue M4-3: Design discussion — scope of 𝓞 and 𝓥 universe variables (#269, closed)¶
Labels: milestone-4-style, design-discussion
Description¶
Overture.Signatures declares variable 𝓞 𝓥 : Level without private. They leak through every downstream module, which is convenient but can be confusing for new contributors shadowing the names.
Tasks¶
- Write up the three options in an ADR or design-discussion issue:
- Keep current behavior; document clearly.
- Make them
privateinOverture.Signatures; downstream modules re-declare. - Move to a dedicated
Overture.UniverseLevelsmodule imported explicitly. - Collect input; pick one.
- Document the decision in STYLE.md.
- Apply consistently.
Acceptance criteria¶
- Decision is recorded (ADR or STYLE.md section).
-
𝓞and𝓥are handled uniformly across the library.
Issue M4-4: Hoist ⟨_⟩ and EqArgs out of Setoid.Algebras.Basic (#337, closed)¶
Labels: enhancement, milestone-4-style, breaking-change, design-discussion
Context¶
Setoid.Algebras.Basic is parameterized by a module-level {𝑆 : Signature 𝓞 𝓥}. Two of its definitions — EqArgs and the polynomial-functor lifting ⟨_⟩ — take their signature as their own explicit argument and do not use the module parameter. When such a name is imported without instantiating the module, Agda still prepends the unused {𝑆} to it. For every other export (Algebra, _^_, 𝔻[_], 𝕌[_], …) the parameter is recovered from context because the name's type mentions 𝑆; but ⟨_⟩ and EqArgs mention it nowhere, so the prepended {𝑆} becomes an unsolvable metavariable the moment either is written by hand at a use site.
This surfaced while implementing Classical.Structures.Monoid: an interp : Func (⟨ Sig-Monoid ⟩ (≡.setoid A)) (≡.setoid A) annotation failed with an UnsolvedConstraints error (_𝑆_ : Signature 0ℓ 0ℓ … blocked), even though every value in scope determined the signature. The current workaround is to avoid hand-writing ⟨_⟩ and rely on copattern inference of the Interp field — which works, but leaves a latent footgun for any future use site that names ⟨_⟩ or EqArgs directly.
The underlying issue is conceptual: the module parameter fixes a fibre Alg(𝑆), which is exactly right for the single-signature meta-theory but wrong for code that ranges over signatures. ⟨_⟩ and EqArgs are signature-generic constructions that happen to live inside the fibre-fixing module.
Proposal¶
Extract EqArgs and ⟨_⟩ (and any other signature-explicit, parameter-unused definitions) into a new non-parameterized module — suggest Setoid/Algebras/Setoid.lagda.md — and have Setoid.Algebras.Basic import them. Their bodies are unchanged (they already take 𝑆 explicitly); only their home changes, so the spurious {𝑆} no longer rides along. Algebra's field Interp : Func (⟨ 𝑆 ⟩ Domain) Domain continues to apply the relocated ⟨_⟩ to the module's 𝑆.
Acceptance criteria¶
-
EqArgsand⟨_⟩live in a non-parameterized module;Setoid.Algebras.Basicre-exports them so existing import sites are unaffected (or, where they must change, the change is mechanical and enumerated in the PR). -
make checkpasses on the wholeSetoid/tree and theDemos/HSPdevelopment. - A throwaway
_ = ⟨ Sig-Monoid ⟩ (≡.setoid ℕ)inClassical/Structures/Monoidelaborates with no unsolved metavariable (then removed). - The copattern workaround in
fromMonoidOps/expand-εstill type-checks (it should be unaffected; this is a regression guard).
Non-goals¶
- Any change to the fibre vs. total-category design of
Algebraitself — that is the separate M11 question (see #). This issue only relocates two signature-generic helpers; it does not touch whether 𝑆is a parameter or an argument ofAlgebra.
Risk¶
Low, but the blast radius is whatever currently imports ⟨_⟩/EqArgs from Basic. Expected to be small (both are nearly internal to Algebra), but the PR should grep for both and re-run make check rather than assume.
Issue M4-5: Signatures as functors — reducts, expansions, and interpretability (#338, closed)¶
Labels: enhancement, milestone-4-style, design-discussion
Summary¶
Make the polynomial-functor / container structure already latent in the foundation first-class, and with it the total-category (∫Alg) view that reducts, expansions, and signature morphisms inherently require — as opposed to the fibre view (Alg(𝑆) for a fixed 𝑆) that the module-parameter convention of Setoid.Algebras.Basic privileges. This is the structural companion to the surgical fix in [M4-4]: where M4-4 relocates the two signature-generic helpers (⟨_⟩, EqArgs) that leak the unused module parameter, [M4-5] builds out the category-theoretic layer that motivates ranging over signatures in the first place. Full design in docs/notes/milestone-signature-functors.md.
Why now¶
The M3-6 (Monoid/Group) work built, by hand, a container-morphism reduct ([Classical.Structures.Reduct][]), an expand-ε dual, and discovered that "reduct-invariance of satisfaction" is what discharges each forgetful projection's theory obligation (the per-structure curried-law pivots in monoid→semigroup and the reindex forgetfuls). It also surfaced that the foundation already is a polynomial-functor formalization without saying so: Signature is a container, ⟨ 𝑆 ⟩ is the polynomial functor P_σ lifted to setoids, Interp is the structure map P_σ(Domain) → Domain, and Term is the initial algebra of A ↦ X ⊎ P_σ(A). M4-5 makes this explicit and reusable, and is the proper home for the Base/Adjunction and Base/Categories orphans currently parked as TBD.
Mathematical core¶
A signature morphism is a container morphism (ι , κ) (ι covariant on symbols, κ contravariant on arities). Signatures and these morphisms form a category Sig. P is a 2-functor Sig → [Setoid,Setoid]; reduct is precomposition with the induced natural transformation; expansion is its copairing dual; reduct-invariance of satisfaction is naturality of the unique fold; reduct has a left adjoint (free expansion); a theory interpretation is a signature morphism into derived operations, with Maltsev conditions as interpretations of small theories.
Subissues¶
- M4-5a Category of signature morphisms; promote
reductto a packaged morphism. (low risk) - M4-5b
⟨_⟩as a functor; induced natural transformations. (low–medium) - M4-5c Reduct as a functor on algebras; upgrade the classical forgetful projections to forgetful functors by supplying the morphism action. (medium)
- M4-5d Free expansion; the
F ⊣ reductadjunction. Distinguish from M3-6's chosenexpand-ε. (high / high-value) - M4-5e Term monad; naturality of the fold; reduct-invariance of satisfaction as a corollary, absorbing M3-6's per-structure pivot proofs. (medium)
- M4-5f Theory interpretations; Maltsev conditions as interpretations; the interpretability quasi-order. (research-grade, exploratory)
- M4-5g Reduct classes of varieties are prevarieties (closed under S, P, not H). (research-grade)
The ordering is a dependency chain: a→b→c→{d,e}, with e gating f and c gating g.
De-risking spikes (before the hard phases)¶
- Spike A (in M4-5c): supply the morphism action for
monoid→semigrouponly and prove it functorial. - Spike B (in M4-5d): construct the free monoid on a semigroup (adjoin a unit) and prove the universal property against
reduct. If this single adjunction is clean with setoid quotients, the general theorem is plausible.
Open questions¶
- Adjunction direction/existence along inclusions that add equations (needs quotients now, cubical HITs later).
- Build on
agda-categoriesvs. stay self-contained (prototype both in M4-5a). - Whether cubical dissolves the M3-5 binary-node-bridge obstruction (an MLTT/
--safeartifact) — a measurable cubical-port (v4.0) payoff if so; M4-5e is the place to measure it. - Keep M4-5f/g on the clone/CSP side (connects to M9-2, Bodirsky–Pinsker), explicitly not the FLRP side.
Relationship to other work¶
Depends on M3 (concrete reduct/expand) and the Setoid.Varieties machinery. Sibling to [M4-4] (the ⟨_⟩/EqArgs parameter-leak fix, which removes friction this milestone would otherwise keep hitting). Connects to M9-2 via interpretability.
Issue M4-5a: Category of signature morphisms (#339, closed)¶
Labels: enhancement, milestone-4-style, category-theory
The current reduct ι κ 𝑨 (Classical.Structures.Reduct) takes the container morphism as two loose arguments. Package the pair (ι , κ) as a first-class SigMorphism 𝑆₁ 𝑆₂ — a record with ι : OperationSymbolsOf 𝑆₁ → OperationSymbolsOf 𝑆₂ (covariant on symbols) and κ : (o : OperationSymbolsOf 𝑆₁) → ArityOf 𝑆₂ (ι o) → ArityOf 𝑆₁ o (contravariant on positions) — and assemble signatures and these morphisms into a category Sig. This is the Abbott–Altenkirch–Ghani container-morphism, specialized to Signature = (OperationSymbolsOf ▷ ArityOf).
The first real subtlety this surfaces is morphism equality: under --safe without funext, two SigMorphisms agreeing pointwise need not be propositionally equal (the same Fin n η-gap that forces the pointwise bundle round-trips), so the category laws may have to be stated against a setoid of morphisms rather than ≡. Settling that is half the value of the issue, since it determines the shape of everything downstream.
Tasks:
+ [ ] Define SigMorphism 𝑆₁ 𝑆₂ (record packaging ι, κ).
+ [ ] Define identity (ι = id, κ = λ _ → id) and composition (ι composes covariantly, κ contravariantly).
+ [ ] Decide the hom-equality (propositional vs. a hom-setoid) and prove the category laws under that choice.
+ [ ] Re-express reduct to consume a SigMorphism, keeping the loose-argument form as a thin wrapper (or deprecating it).
+ [ ] Decision spike: realize Sig both as an agda-categories Category and as a self-contained record; record which to standardize on.
Non-goals: any action on algebras (that is M4-5-3); morphisms into derived operations (that is M4-5-6, where κ's codomain becomes terms rather than symbols).
Acceptance criteria:
+ [ ] reduct (id-morphism) 𝑨 agrees with 𝑨 (definitionally on the carrier; up to the chosen hom-equality on operations).
+ [ ] reduct (ψ ∘ φ) agrees with reduct φ ∘ reduct ψ.
+ [ ] The category laws type-check under the chosen morphism-equality.
References: Abbott, Altenkirch, Ghani, Containers: constructing strictly positive types; ADR-002 v2 §5.
Issue M4-5b: ⟨_⟩ as functor and induced natural transformations (#340, closed)¶
Labels: enhancement, milestone-4-style, category-theory
Make explicit that ⟨ 𝑆 ⟩ : Setoid → Setoid (Setoid.Algebras.Basic) is the polynomial/container functor P_σ and is functorial in the carrier (its action on a setoid map is post-composition on the position function). Then show that a SigMorphism (ι , κ) : 𝑆₁ → 𝑆₂ induces a natural transformation ⟦ι,κ⟧ : ⟨ 𝑆₁ ⟩ ⟹ ⟨ 𝑆₂ ⟩, given on components by (o , args) ↦ (ι o , args ∘ κ o) — which is exactly the data reduct already precomposes into Interp. Finally, show the assignment SigMorphism ↦ natural transformation is itself functorial (identity to identity, composite to vertical composite), i.e. ⟦_⟧ is a functor Sig → [Setoid , Setoid].
This is the issue where the "the foundation already is a polynomial-functor formalization" observation stops being a remark and becomes a checked statement. It is the natural-transformation layer that [M4-5e]'s fold-naturality result will sit on top of.
Tasks:
+ [ ] ⟨ 𝑆 ⟩ functorial in the carrier (map-law + functoriality).
+ [ ] The induced natural transformation ⟦ι,κ⟧; prove its naturality square.
+ [ ] Functoriality of ⟦_⟧ (preserves identity and composition of SigMorphisms).
Acceptance criteria:
+ [ ] The naturality square for ⟦ι,κ⟧ commutes.
+ [ ] ⟦ id-morphism ⟧ is the identity natural transformation; ⟦ ψ ∘ φ ⟧ is the vertical composite, up to the chosen equality.
References: Gambino, Kock, Polynomial functors and polynomial monads.
Issue M4-5c: Reduct as functor on algebras (#341, closed)¶
Labels: enhancement, milestone-4-style, category-theory
For a fixed φ : SigMorphism 𝑆₁ 𝑆₂, promote reduct φ : Alg(𝑆₂) → Alg(𝑆₁) from an object map to a functor: its action on an 𝑆₂-homomorphism is the same underlying setoid map, whose 𝑆₁-homomorphism condition transfers because the reduct's operations are φ-images of 𝑆₂'s (the square commutes by the same κ-reindex). Then resolve the M3-6 note that monoid→semigroup and friends are "object maps of forgetful functors, not yet functors" by supplying the morphism action, packaging each classical forgetful as a genuine functor between the structures' categories.
This requires a category of 𝑆-algebras in the first place. Setoid.Homomorphisms supplies the homs; this issue must assemble Alg(𝑆) as a category (or reuse one if it already exists), and observe that a morphism of Σ-typed classical structures is just an algebra hom (the equational-witness component carries no additional morphism data). That assembly is the main dependency risk and should be scoped explicitly at the top of the PR.
Tasks:
+ [ ] Assemble Alg(𝑆) as a category over Setoid.Homomorphisms (or confirm/reuse an existing one).
+ [ ] reduct φ as a functor: morphism action + functor laws.
+ [ ] Package monoid→semigroup, commutativeMonoid→monoid, commutativeSemigroup→semigroup (and the Sig-Group analogues once they land) as forgetful functors, with the reindex forgetfuls reusing the M4-5-1 identity-ish morphism.
Non-goals: a left adjoint [M4-5d] (#342); the equational-class semantics [M4-5g] (#345)).
Acceptance criteria:
+ [ ] reduct φ satisfies the functor laws.
+ [ ] At least monoid→semigroup type-checks as a functor and its action on a concrete monoid hom reduces correctly.
References: Setoid.Homomorphisms; ADR-002 v2 §5.
Issue M4-5d: Free expansion; the F ⊣ reduct adjunction (#342, closed)¶
Labels: enhancement, milestone-4-style, category-theory, research-exploratory
Construct the left adjoint F : Alg(𝑆₁) → Alg(𝑆₂) to reduct φ along a symbol-adjoining inclusion φ (one that adds operation symbols and no equations), exhibiting the free 𝑆₂-algebra on an 𝑆₁-algebra. The sharpest content of the issue is the contrast with M3-6's expand-ε: expand-ε adjoins ε as a chosen element of the existing magma carrier — a specific section of the reduct, not a universal one — whereas the free expansion freely adjoins a new generator for each added symbol, enlarging the carrier. Making F ⊣ reduct precise is what tells you when "this magma is secretly a monoid" (a section) and "the free monoid on this magma" (the adjoint) are the same and when they diverge.
Inclusions that adjoin equations (not just symbols) need a quotient for the left adjoint — the free algebra modulo the new equations — which wants setoid quotients now and is a candidate cubical-HIT payoff later. Scope this issue to symbol-adjoining inclusions; flag equation-adjoining adjoints as a follow-up.
Spike (do this before the general construction): build F for one concrete symbol-adjoining inclusion — freely adjoin a unit to a semigroup, i.e. the free monoid on a semigroup — and verify the universal property against reduct. If a single adjunction is clean under setoid quotients, the general theorem is plausible; if it is not, that is the signal to re-scope.
Tasks:
+ [ ] Spike: F for the free-unit inclusion; unit, counit, and triangle identities for that one case.
+ [ ] Generalize F to arbitrary symbol-adjoining φ (stretch).
+ [ ] Document precisely how expand-ε relates to F (a section vs. the adjoint), updating the M3-6 prose that currently calls expand-ε "the expand half of the reduct/expand dual."
Non-goals: equation-adjoining left adjoints (deferred; needs quotients/HITs).
Acceptance criteria:
+ [ ] The spike adjunction's triangle identities type-check.
+ [ ] A design note distinguishing expand-ε from F.
Issue M4-5e: Term monad; naturality of the fold; reduct-invariance of satisfaction (#343, closed)¶
Labels: enhancement, milestone-4-style, category-theory
Establish Term 𝑆 : Setoid → Setoid as a monad (unit ℊ, multiplication by substitution) and the environment interpretation ⟦_⟧ as the unique fold out of the term algebra, natural in the carrier. The target theorem is reduct-invariance of satisfaction: for φ : 𝑆₁ → 𝑆₂, an 𝑆₂-algebra 𝑨, and an 𝑆₁-equation s ≈ t, reduct φ 𝑨 ⊧ s ≈ t is equivalent to 𝑨 ⊧ φ✶ s ≈ φ✶ t (the φ-translation of terms), and this is precisely naturality of the fold with respect to the [M4-5b] induced natural transformation.
This is the payoff issue. As a corollary it absorbs the per-structure curried-law pivots written by hand in M3-6 — monoid→semigroup's thm, and the analogous obligations for the reindex forgetfuls — into instances of one lemma. It also bears directly on the M3-5 negative finding: the per-signature interp-nodeₙ families are the manual unfolding that fold-naturality systematizes, and this issue should measure whether the binary-node-bridge obstruction (the refl-match on a neutral ArityOf 𝑆 f ≡ Fin 2, rejected by the without-K unifier) survives at the functorial level or dissolves — the answer is a concrete data point for the cubical-port (v4.0) cost/benefit.
Tasks:
+ [ ] Term 𝑆 monad laws (left/right unit, associativity of substitution).
+ [ ] Fold (⟦_⟧) naturality in the carrier.
+ [ ] The reduct-invariance-of-satisfaction lemma.
+ [ ] Re-derive monoid→semigroup's Th-Semigroup obligation from the lemma as a regression demonstration (do not delete the bespoke proof until the general one lands and type-checks).
+ [ ] Record whether the M3-5 node-bridge obstruction persists functorially.
Acceptance criteria: + [ ] The reduct-invariance lemma type-checks. + [ ] The Monoid forgetful's theory obligation is re-provable through it.
References: the M3-5 finding on interp-node (per-signature, proof-free); ADR-002 v2 §1.
Issue M4-5f: Theory interpretations; Maltsev conditions as interpretations; the interpretability quasi-order (#344, closed)¶
Labels: milestone-4-style, research-exploratory
Scope note: this is a research-tracking issue. The task list below is provisional and deliberately shallow — committing to an internal structure before M4-5-1..5 exist would be premature. The deliverable for this issue is a definition, one or two worked instances, and a design note that lets a later issue commit to the real development.
Generalize the symbol-to-symbol SigMorphism of M4-5-1 to a theory interpretation T₁ → T₂: a signature morphism into the derived (term) operations of T₂ under which every T₁-equation becomes a T₂-theorem. Maltsev conditions — a Maltsev term, a majority term, a near-unanimity term — are then exactly interpretations of small theories (e.g. the one-ternary-symbol theory with the Maltsev equations) into a given variety, and the interpretability relation induces the Garcia–Taylor quasi-order on varieties.
This sits squarely on the clone/CSP side of the library and connects forward to M9-2 (infinitary CSP over ω-categorical templates, the Bodirsky–Pinsker program). It is explicitly not FLRP work — the interpretability/Maltsev/clone material and the Finite Lattice Representation Problem are kept in separate research tracks, and conflating them is an error to flag in review.
Provisional tasks: + [ ] Reading pass: Garcia–Taylor, The Lattice of Interpretability Types of Varieties; standard Maltsev-condition references; Bodirsky for the CSP linkage. + [ ] Define theory interpretation (signature morphism into derived operations + equation-preservation). + [ ] One worked instance (e.g. the Maltsev-term theory interpreted into a concrete congruence-permutable variety, or just the formal statement). + [ ] Design note scoping the real development and its dependence on [M4-5e] (#343).
Acceptance criteria (loose): a checked definition, at least one interpretation instance, and a written scope note. No claim about the full quasi-order is in scope here.
Issue M4-5g: Reduct classes of varieties (prevarieties) (#345, closed)¶
Labels: milestone-4-style, research-exploratory
Scope note: research-tracking, like [M4-5f] (#344). Prove the tractable half (S, P) and document the rest; do not over-specify before the dependencies land.
For a variety 𝒱 of 𝑆₂-algebras and φ : 𝑆₁ → 𝑆₂, the reduct class reduct φ (𝒱) is closed under subalgebras and products but not, in general, homomorphic images — so it is a prevariety, not a variety. The S- and P-closure follow structurally from reduct φ being a functor [M4-5c] (#341) that preserves the relevant subobjects and limits, together with reduct-invariance [M4-5e] (#343); the failure of H-closure is the interesting negative and is best recorded as a concrete counterexample.
Like [M4-5f], this is clone/variety-theoretic and CSP-adjacent, not FLRP.
Provisional tasks:
+ [ ] State the theorem against the Setoid.Varieties S/H/P machinery.
+ [ ] Prove reduct preserves S (subalgebras).
+ [ ] Prove reduct preserves P (products).
+ [ ] Record the ¬H part as a documented counterexample, or defer with a written rationale.
Acceptance criteria (loose): S and P parts type-check; the ¬H situation is documented.
References: Burris, Sankappanavar, A Course in Universal Algebra (reducts; SP-closure).
Issue M4-6: Consolidate the duplicate Op operation type into one canonical declaration (#354, closed)¶
Labels: enhancement, milestone-4-style, breaking-change
Context¶
The library currently carries two declarations of the operation type Op, with identical bodies but opposite parameter order:
Overture.Operations.Op A I = (I → A) → A— carrier first.Classical.Operations.Op I A = (I → A) → A— arity first.
They are the same type up to argument order, so this is a "one canonical form per concept" violation (the M4 exit criterion explicitly targets synonym pairs in the public API). The arity-first order has proved the more useful of the two: Op (Fin 2) partially applies as "binary operation," independent of any carrier, which is the right convention for the Curry/Uncurry/pair family in Classical.Operations.
Why this issue exists (and why it is deferred from #353)¶
This surfaced in #353, which adds Overture.Cayley (a Cayley-table construction for finite operations). That PR deliberately types a binary operation as a bare Fin n → Fin n → Fin n rather than either Op, precisely so as not to spread the unresolved convention clash into a new module before it is settled. A note at the end of Overture.Cayley points here. The consolidation has a wide blast radius (Op is foundational and used throughout Classical/), so it belongs in the M4 style sweep rather than in an examples-focused PR.
Decision to implement¶
Consolidate to a single canonical Op in Overture.Operations, using the arity-first convention Op I A = (I → A) → A, and have Classical.Operations re-export it (deprecating its local copy under the stable-API discipline rather than deleting it outright).
Tasks¶
- Adopt the canonical
Op : Type 𝓥 → Type α → Type _withOp I A = (I → A) → AinOverture.Operations; update that module's prose, and adjustπandarity[_]to the new argument order. - Re-export the canonical
OpfromClassical.Operations; mark the old arity-first local definition with aWARNING_ON_USAGEdeprecation for at least one minor cycle (it already matches the canonical order, so this is mostly a relocation). - Audit every
Opuse site for the carrier-first vs arity-first flip and migrate; the carrier-first uses (whatever currently importsOverture.Operations.Op) are the ones that change. - Decide whether
pair/Curry₂/Uncurry₂(currently inClassical.Operations) move down toOverturealongside the canonicalOp, or stay inClassical.Operations; record the rationale. - Re-express
Overture.Cayley.⟦_⟧and the decidable-law checkers over the canonicalOpif it reads better than the bareFin n → Fin n → Fin n, or record why the finite case keeps the plain function type. - Update the canonical symbol/notation table in
docs/STYLE_GUIDE.mdto record the singleOpand its argument-order convention.
Acceptance criteria¶
- Exactly one
Opdeclaration in the public API; no duplicate/synonym remains. -
make checkpasses across the whole tree. - Any removed/relocated public name goes through a
WARNING_ON_USAGEdeprecation cycle rather than a hard break. - The
docs/STYLE_GUIDE.mdnotation table matches the consolidatedOp.
Risk¶
Low conceptually but wide: Op is foundational, so the PR should grep every use site, flip carrier-first uses, and re-run make check rather than assume the blast radius is small.
Issue M4-7: V exposes eight unconstrained universe-level parameters; provide a common-case specialization (#359, closed)¶
Labels: milestone-4-style
Context¶
Setoid.Varieties.Closure.V is defined in a module parameterized by eight universe levels:
module _ {α ρᵃ β ρᵇ γ ρᶜ δ ρᵈ : Level} where
V : ∀ ℓ ι → Pred(Algebra α ρᵃ) (a ⊔ ov ℓ) → Pred(Algebra δ ρᵈ) (d ⊔ ov(a ⊔ b ⊔ c ⊔ ℓ ⊔ ι))
V ℓ ι 𝒦 = H{γ}{ρᶜ}{δ}{ρᵈ} (a ⊔ b ⊔ ℓ ⊔ ι) (S{β}{ρᵇ} (a ⊔ ℓ ⊔ ι) (P ℓ ι 𝒦))
The four intermediate levels β ρᵇ γ ρᶜ are genuinely internal to the H ∘ S ∘ P composition — they appear in neither the input algebra (α, ρᵃ) nor the output algebra (δ, ρᵈ).
Where it bit¶
Writing a natural type signature for "the variety generated by a concrete algebra" fails with unsolved metavariables, because β ρᵇ γ ρᶜ are not determined by anything in the signature:
ℕ∈V : 𝑨₀ ∈ V 0ℓ (ov 0ℓ) 𝒦₀ -- unsolved metas: β ρᵇ γ ρᶜ
In Examples.Setoid.HSPCommutativeMonoid (PR #358) I had to introduce a 𝕍 alias pinning all eight implicits to 0ℓ positionally:
𝕍 : Pred (Algebra 0ℓ 0ℓ) (ov (ov 0ℓ))
𝕍 = V {0ℓ}{0ℓ}{0ℓ}{0ℓ}{0ℓ}{0ℓ}{0ℓ}{0ℓ} 0ℓ (ov 0ℓ) 𝒦₀
This is a real papercut for anyone instantiating the variety machinery at a fixed algebra.
Suggested fix¶
- Provide a common-case specialization, e.g.
V′ : ∀ ℓ ι → Pred(Algebra α ρᵃ)(a ⊔ ov ℓ) → Pred(Algebra α ρᵃ) _that collapses the intermediate universes to those of the input/output algebra (the overwhelmingly common case where a class and the generated variety live at the same levels). - Alternatively, make
β ρᵇ γ ρᶜcomputed fromα ρᵃ δ ρᵈ ℓ ι(so they are no longer free implicits) rather than independent module parameters, if the H/S/P composition permits. - At minimum, document the eight-parameter shape and the pinning idiom in
docs/STYLE_GUIDE.md, and ship the𝕍-style helper as library API so examples/tests need not re-derive it.
Acceptance criteria¶
- A downstream
𝑨 ∈ V … 𝒦membership at a fixed algebra type-checks without manually pinning intermediate levels. make checkpasses.
Issue M4-8: V-expa cannot infer its class 𝒦 from a membership proof; offer an explicit-argument variant (#360, closed)¶
Labels: milestone-4-style
Context¶
Setoid.Varieties.Closure.V-expa has the _⊆_-based signature
V-expa : ∀ ℓ ι → {𝒦 : Pred (Algebra α ρᵃ)(a ⊔ ov ℓ)} → 𝒦 ⊆ V ℓ ι 𝒦
where 𝒦 ⊆ V ℓ ι 𝒦 unfolds to ∀ {x} → x ∈ 𝒦 → x ∈ V ℓ ι 𝒦. Both the class 𝒦 and the element x are implicit and must be recovered from a single membership argument.
Where it bit¶
Applying V-expa to a membership proof leaves 𝒦 (and x) as a higher-order unification problem _𝒦 _x ≟ (type of the proof), which Agda cannot solve — especially once the class predicate reduces. In Examples.Setoid.HSPCommutativeMonoid (PR #358), V-expa 0ℓ (ov 0ℓ) 𝑨₀∈𝒦₀ failed; I had to both (a) make the singleton class a non-reducing one-constructor data family and (b) pass {𝒦 = 𝒦₀} explicitly:
ℕ∈V = V-expa 0ℓ (ov 0ℓ) {𝒦 = 𝒦₀} 𝑨₀∈𝒦₀
Suggested fix¶
- Add an explicit-argument variant, e.g.
V-expa′ : ∀ ℓ ι (𝒦 : Pred (Algebra α ρᵃ)(a ⊔ ov ℓ)) {𝑨} → 𝑨 ∈ 𝒦 → 𝑨 ∈ V ℓ ι 𝒦
so the class is supplied directly rather than back-inferred through _⊆_.
+ Consider applying the same treatment to the other _⊆_/_⊫_-stated closure lemmas (S-expa, H-expa, P-expa) for consistency.
+ Keep the _⊆_ form as the abstract statement; the explicit variant is the ergonomic entry point.
Acceptance criteria¶
𝑨 ∈ V ℓ ι 𝒦is derivable from𝑨 ∈ 𝒦without manually supplying{𝒦 = …}or reshaping the class to avoid reduction.make checkpasses.
Issue M4-9: V-id1 forces explicit {p}{q} because _⊫_/_⊧_ unfold eagerly during unification (#361, closed)¶
Labels: milestone-4-style
Context¶
Setoid.Varieties.Preservation.V-id1 lifts an identity from a class to the variety it generates:
V-id1 : 𝒦 ⊫ (p ≈̇ q) → V ℓ ι 𝒦 ⊫ (p ≈̇ q)
with p q module-level implicits. The equation (p ≈̇ q) appears, intact, in the type of the argument.
Where it bit¶
When checking V-commutative : 𝕍 ⊫ (x·y ≈̇ y·x) against V-id1 … 𝒦₀⊫comm (PR #358), Agda did not unify the equation at the injective Eq level (_p ≈̇ _q ≟ x·y ≈̇ y·x). Instead it unfolded _⊫_ → _⊧_ → Equal → ⟦_⟧, producing stuck constraints of the form
⟦ 𝑨 ⟧ _p ρ ≈ ⟦ 𝑨 ⟧ (node ∙-Op (λ { 0F → ℊ 0F ; 1F → ℊ 1F })) ρ (blocked on _p)
i.e. the equation's lhs/rhs became metavariables blocked behind the unfolded interpreter. I had to pin them by hand:
V-commutative = V-id1 {ℓ = 0ℓ} {ι = ov 0ℓ} {𝒦 = 𝒦₀} {p = x·y} {q = y·x} 𝒦₀⊫comm
even though p, q, and 𝒦 are all visible in the argument's type.
Suggested fix¶
- Make
_⊧_/Equal(and hence_⊫_) less reduction-happy so the equation unifies as anEq, not as an unfoldedEqual— e.g. wrapEqualin arecord/ make itabstract, or mark the relevant definitions so the unifier prefers theEqconstructor. (This likely helpsV-id2,S-id1,H-id1, and friends too.) - Or restate the preservation lemmas to take the equation
Eqas an explicit argument, so callers never rely on back-inference through_⊫_.
Acceptance criteria¶
V ℓ ι 𝒦 ⊫ (p ≈̇ q)is derivable from𝒦 ⊫ (p ≈̇ q)without manually supplying{p}{q}when they already appear in the argument's type.make checkpasses.
Issue M4-10: Substitution _[_] does not compute through tuple arguments; add a substitution-lemma kit (#362, closed)¶
Labels: milestone-4-style
Context¶
In Setoid.Terms.Basic, term substitution pushes into nodes pointwise:
(node f ts) [ σ ] = node f (λ i → ts i [ σ ])
When ts is a finite tuple built from a pattern-matching lambda (the natural way to write a binary term, s · t = node ∙-Op (λ { 0F → s ; 1F → t })), the result node f (λ i → ts i [ σ ]) is not definitionally equal to a freshly rebuilt term (s [ σ ]) · (t [ σ ]) — a pattern-matching lambda does not reduce under a variable index i, and bridging the two functions needs function extensionality, which is unavailable under --safe/--cubical-compatible.
Where it bit¶
This blocks the obvious way to instantiate an equation at compound terms. In Examples.Setoid.FreeSemigroup (PR #358) the natural statement
assoc▹ : (p q r : Term (Fin 4)) → E ⊢ Fin 4 ▹ ((p · q) · r) ≈ (p · (q · r))
assoc▹ p q r = sub (hyp 0F) σ -- σ 0F = p; 1F = q; 2F = r
fails: sub produces a goal in [ σ ]-form (node ∙-Op (λ i → … [ σ ])) that will not match the readable (p · q) · r. As a result I could not write a clean four-fold reassociation and had to restrict the term-rewriting demo to redexes that match the law literally (no sub).
Suggested fix¶
- Ship a small substitution-lemma kit, proved up to derivable equality
_⊢_▹_≈_(or propositional_≡_where it holds), e.g.: []-node:node f ts [ σ ] ≈ node f (λ i → ts i [ σ ])and a congruence[]-congfor rebuilding tuples;[]-∘(substitution composition) and[]-ℊ.- And/or offer a
Vec-based (or explicitly enumerated) argument representation for fixed finite arities under which substitution commutes definitionally, so(s · t) [ σ ]reduces to(s [ σ ]) · (t [ σ ])on the nose. - Document the idiom (and the funext obstruction) so users do not rediscover it.
Acceptance criteria¶
- An equation can be instantiated at compound terms via
suband the result matches a readable, rebuilt term (definitionally, or via a one-line lemma). - A multi-step reassociation example (e.g.
((a·b)·c)·d ≈ a·(b·(c·d))) type-checks cleanly. make checkpasses.
Issue M4-11: No generic smart-constructor for a concrete Setoid Algebra; add one (#363, closed)¶
Labels: milestone-4-style
Context¶
Building a concrete Setoid.Algebras.Basic.Algebra requires hand-writing the interpretation Func (⟨ 𝑆 ⟩ Domain) Domain, including its cong over the Σ/EqArgs encoding of ⟨ 𝑆 ⟩:
ℕ∸-magma : Algebra 0ℓ 0ℓ
ℕ∸-magma = record { Domain = ≡.setoid ℕ ; Interp = interp }
where
interp : Func (⟨ Sig-Magma ⟩ (≡.setoid ℕ)) (≡.setoid ℕ)
interp ⟨$⟩ (∙-Op , args) = args 0F ∸ args 1F
cong interp {∙-Op , _} {.∙-Op , _} (refl , args≈) = ≡.cong₂ _∸_ (args≈ 0F) (args≈ 1F)
The {∙-Op , _}{.∙-Op , _}(refl , args≈) boilerplate recurs in every concrete algebra (it appears in Examples.Setoid.FreeMagma, Examples.Setoid.FiniteQuotient, and across Classical.Bundles.*).
Where it bit¶
The Classical layer has structure-specific smart-constructors (opsToMagma, eqsToMonoid, eqsToCommutativeMonoid, …), but there is no generic builder at the Setoid layer. Every example/test that needs a one-off concrete algebra re-derives the interp + cong plumbing.
Suggested fix¶
- Add a generic builder in
Setoid.Algebras.Basic, e.g. for a≡-carrier:
mkAlgebraₚ : (A : Type α)
→ (f : (o : ∣ 𝑆 ∣) → (∥ 𝑆 ∥ o → A) → A)
→ Algebra α 0ℓ
deriving Domain = ≡.setoid A and the cong automatically (it is ≡-congruence of f in each argument).
+ Optionally a setoid-general version mkAlgebra taking a carrier Setoid plus a per-operation cong obligation, packaging the (refl , args≈) destructuring once.
+ Re-express a couple of existing concrete algebras through it as a regression demonstration.
Acceptance criteria¶
- A concrete finite/
≡-carrier algebra can be defined without writing the⟨ 𝑆 ⟩-congboilerplate by hand. make checkpasses.
Issue M4-12: Re-export _,_ from Setoid.Algebras to avoid a misleading Σ-constructor scope error (#364, closed)¶
Labels: milestone-4-style
Context¶
The carrier of ⟨ 𝑆 ⟩ ξ is an Agda.Builtin.Sigma.Σ, so an interpretation clause pattern-matches as (o , args). This requires the pair constructor _,_ to be in scope.
Where it bit¶
If _,_ is not imported (easy to forget when you have only imported the signature and algebra machinery), the clause
interp ⟨$⟩ (∙-Op , args) = …
fails with the misleading error
∙-Op is not a constructor of the datatype Agda.Builtin.Sigma.Σ
which points at ∙-Op rather than at the missing _,_, and gives no hint that the fix is open import Data.Product using ( _,_ ). I hit this immediately when writing the first example in PR #358.
Suggested fix¶
- Re-export
_,_(and likelyΣ-syntax) fromSetoid.Algebras(and/orSetoid.Algebras.Basic), since any consumer pattern-matching on⟨ 𝑆 ⟩carriers needs it. This is the smallest change and removes the trap for example/test authors. - Optionally, note the requirement in the
Setoid.Algebras.Basicprose next to the⟨_⟩definition.
Acceptance criteria¶
- Importing
Setoid.Algebrasis sufficient to pattern-match(o , args)on a⟨ 𝑆 ⟩carrier without a separateData.Productimport. make checkpasses.
Issue M4-13: Reorganize modules: top-level Order/ tree and Setoid.Congruences promotion (#377, closed)¶
Labels:
Description¶
Two module-placement corrections that came out of the #373/#375 review discussion. Both are about putting things on the footing the library's own conventions imply.
(a) Promote congruences to a sibling of Setoid.Algebras. The library's child-vs-sibling convention is "the definition of the algebra type is a child of Algebras (Basic, Products); a major construction built on algebras is a sibling" — which is why Homomorphisms, Subalgebras, Relations, Terms, Varieties are all siblings even though they depend crucially on algebras. Congruences are the dual of subalgebras (quotients ↔ subobjects), so by that rule they belong next to Setoid.Subalgebras, not buried under Setoid.Algebras (where they currently sit only by inheritance from legacy Base.Algebras.Congruences).
(b) Move the order-theoretic lattice infrastructure to a new top-level Order/ tree. The CompleteLattice record is pure order theory — it imports only Level and Relation.Binary, with zero dependency on algebras or setoids. A top-level Order/ tree (sibling of Setoid/, Classical/, Overture/) is its honest home, and it makes the tree path self-documenting: Order.* is unmistakably the order-theoretic notion of lattice, fully disambiguated from Classical.*.Lattice, which is the distinct equational-algebra notion (a peer of groups/rings). There is no real redundancy between the two — they are the two classical presentations of "lattice," equivalent only via a theorem.
Target layout¶
src/
├── Order/
│ ├── Order.lagda.md (barrel; prose cross-refs Classical.*.Lattice)
│ └── CompleteLattice.lagda.md (moved from Setoid.Algebras.Lattices.CompleteLattice)
├── Setoid/
│ ├── Algebras/ (Basic, Products)
│ ├── Congruences/ (Basic, Lattice, Generation, CompleteLattice) ← promoted
│ ├── Subalgebras/ (…, CompleteLattice)
│ └── Relations/ Homomorphisms/ Terms/ Varieties/ …
└── Classical/ (… .Lattice modules untouched)
Tasks¶
- Create top-level
Order/tree:git mvSetoid.Algebras.Lattices.CompleteLattice→Order.CompleteLattice; add theOrderbarrel; removeSetoid.Algebras.Lattices(.lagda.md). - Promote
Setoid.Algebras.Congruences.*→Setoid.Congruences.*(Basic,Lattice,Generation,CompleteLattice); add theSetoid.Congruencesbarrel; drop theCongruencesre-export from theSetoid.Algebrasbarrel. - Rewire all imports:
Setoid.Homomorphisms.Kernels, theSetoid.Algebrasbarrel,Setoid.Subalgebras.CompleteLattice(now importsOrder.CompleteLattice), the Congruences submodules' self-references, and the examples (Examples.Setoid.{CongruenceLattice, FiniteQuotient, SubalgebraLattice, SubgroupLattice}). - Update module titles, nav links, and the
Order ↔ Classical.*.Latticecross-reference prose. nix develop --command make checkpasses.
Acceptance criteria¶
- Tree matches the target layout;
Order.CompleteLatticeandSetoid.Congruences.*resolve. - Full library type-checks (exit 0).
- Cross-reference prose added in both directions (
Order↔Classical).
Notes¶
- An algebraic ⇄ order-theoretic lattice bridge (proving the two presentations agree) is a genuinely valuable follow-up, but a theorem, not part of this reorg — track separately.
- Pure module-move + import-rewrite refactor; no proofs change. To be done on branch
377-m4-13-order-reorgafter #375 and #376 merge, so those reviews aren't rebased mid-flight.
Issue M4-14: Free expansion on raw algebra cats: symbol-adjoining left adjoint via term-algebra quotient (#400)¶
Labels: enhancement, milestone-4-style, category-theory, research-exploratory
M4-5d (#342, merged via #399) landed the free-expansion adjunction at the theory-satisfying (bundle) level: adjoinUnit ⊣ forgetUnit between Semigroups and Monoids, where the monoid equations collapse the free expansion to first-order normal forms (Maybe 𝕌[ 𝑺 ]) and no quotient is needed. This issue is the deferred stretch task of #342, plus the follow-up it flagged: construct the left adjoint to reductF φ : Alg(𝑆₂) → Alg(𝑆₁) for an arbitrary symbol-adjoining φ : SigMorphism 𝑆₁ 𝑆₂ on the raw algebra categories (no theories), and, on the same quotient infrastructure, the equation-adjoining left adjoint. The construction plan below is lifted from docs/notes/m4-5d-free-expansion.md, which records why the raw level is where setoid quotients genuinely enter.
Construction plan (raw, symbol-adjoining)¶
With no equations available, nothing collapses formal products involving the new symbols (already for Sig-Magma ↪ Sig-Monoid, a ∙ ε and ε ∙ ε are genuinely new elements), so the free 𝑆₂-algebra on a raw 𝑆₁-algebra 𝑨 is a setoid quotient of the term algebra:
- Carrier.
F 𝑨 = T_{𝑆₂}(𝕌[ 𝑨 ]) / Θ_φ(𝑨), whereΘ_φ(𝑨)is the congruence generated by the𝑆₁-operation graph of𝑨: for each symboloof𝑆₁and each tuplea : ArityOf 𝑆₁ o → 𝕌[ 𝑨 ], identifynode (ι φ o) (λ i → ℊ (a (κ φ o i)))withℊ ((o ^ 𝑨) a)— exactly the identifications that make the unit a homomorphism, and only those.Setoid.Termsprovides the term algebra andSetoid.Congruences.Generationthe generated congruence. - Unit.
ℊinto the quotient, an𝑆₁-homomorphism by the generating relations. - Counit and extension. The fold of
T_{𝑆₂}(𝕌[ 𝑨 ])into an𝑆₂-algebra𝑩along an𝑆₁-homomorphism𝑨 → reduct φ 𝑩, shown to respectΘ_φ(𝑨)(the generators map to instances of the homomorphism's compatibility); uniqueness by induction on terms. - Adjunction. Instantiate the componentwise
Adjunctionrecord ofSetoid.Categories.Adjunction(unit, counit, naturality squares,zig/zag) againstreductF φfromClassical.Categories.Reduct, between the raw categoriesAlg 𝑆₂ α ρandAlg 𝑆₁ α ρofSetoid.Categories.Algebra. Mind the level bookkeeping: the quotient carrier must land back at levels theAlgcategories share, the same constraint that forced the hand-rolled level-ρrelation inClassical.Categories.AdjoinUnit.
De-risk spike-first, as #342 did: build F for Sig-Magma ↪ Sig-Monoid on raw algebras — the free Sig-Monoid-algebra on a raw magma, whose carrier is genuinely bigger than Maybe — before generalizing over φ.
Equation-adjoining stage¶
For an inclusion into a theory (𝑆₂ , Th-X) the left adjoint is the same construction with Th-X's equations, instantiated over T_{𝑆₂}(𝕌[ 𝑨 ]) under all environments, added to the generators of the congruence. This contains the bundle-level adjoinUnit of #342 as the special case in which the quotient happens to have computable normal forms.
Cubical payoff measurement¶
The quotient is a candidate cubical-HIT payoff at v4.0 (ADR-003). Record what the setoid-quotient construction costs — lemma count, whether the proof terms stay transport-free — so the eventual port comparison is quantitative; this is the same measurement hook the milestone note attaches to M4-5e's binary-node-bridge question.
Tasks:
+ [ ] Raw spike: the free Sig-Monoid-algebra on a raw magma; unit, counit, and triangle identities against reductF magma↪monoid between the raw Alg categories.
+ [ ] Generalize F to an arbitrary symbol-adjoining φ : SigMorphism 𝑆₁ 𝑆₂.
+ [ ] Equation-adjoining left adjoint on the same quotient infrastructure (stretch).
+ [ ] Record the cubical-HIT cost-comparison data in docs/notes/m4-5d-free-expansion.md (or a successor note).
Non-goals: re-doing the bundle-level adjunction of #342; theory interpretations and the interpretability quasi-order (M4-5f, #344).
Acceptance criteria:
+ [ ] The raw spike adjunction's triangle identities type-check under --cubical-compatible --exact-split --safe.
+ [ ] The general symbol-adjoining F ⊣ reductF φ type-checks, or a design note documents the precise obstruction and the re-scope decision.
References: #338 (the M4-5 epic), #342 / #399 (the bundle-level spike this defers from), docs/notes/m4-5d-free-expansion.md § "Why the spike lives at the bundle level" and § Follow-ups, ADR-003, ADR-006.
Issue M4-15: Generalize finite op-law deciders to DecSetoid + exhaustive-search witness (#357, closed)¶
Labels: enhancement, milestone-4-style
Summary¶
The decidable equational-law checkers in Overture.Operations.Properties (Associative?, Commutative?, Idempotent?, the identity/inverse laws, and the two-operation Absorbsˡ?/Absorbsʳ?/Distributesˡ?/Distributesʳ?) are currently stated only for a finite carrier Fin n with propositional equality _≡_. Their decidability rests on exactly two ingredients:
Data.Fin.Properties.all?— the carrier is exhaustively searchable; and_≟_— equality on the carrier is decidable.
Neither ingredient is specific to Fin n or to _≡_. This issue proposes generalizing the checkers to an arbitrary DecSetoid (a setoid whose _≈_ is decidable) equipped with an exhaustive-search / finiteness witness for the carrier.
Why¶
-
Reuse. The checkers would then apply to any decidable, exhaustively-searchable carrier — not only
Fin n— so downstream finite-algebra work (CSP templates, the FLRP examples, finite quotients) could decide laws over whatever carrier is natural, without first coercing toFin n. -
A principled home. Stated over a
DecSetoid, the checkers become genuinely setoid-level content and would earn a home in theSetoid/tree (e.g. alongsideSetoid.Relations.*), rather than the≡/Fin-onlyOverture/layer where they live today. (The decision to keep the concrete versions inOverture.Operations.Propertiesfor now is recorded in #356.) -
Connection to M9-1 (Escardó's exhaustive search). The right abstraction for "exhaustively searchable" is precisely the subject of Martín Escardó's work —
Searchable/exhaustibletypes, where even some infinite types (e.g.ℕ∞, the one-point compactification ofℕ) admit a total search functional. Generalizing the deciders against such aSearchable/Exhaustibleinterface (rather than hard-codingFin'sall?) would let the same law-checkers run over those carriers, and would dovetail with the planned M9-1 work. See Escardó, Infinite sets that admit fast exhaustive search (LICS 2007) and Seemingly impossible functional programs.
Sketch¶
Roughly, replace
module _ {n : ℕ} (_·_ : Fin n → Fin n → Fin n) where
Associative? : Dec (∀ a b c → (a · b) · c ≡ a · (b · c))
Associative? = all? (λ a → all? (λ b → all? (λ c → ((a · b) · c) ≟ (a · (b · c)))))
with something parameterized over a DecSetoid S and a search/finiteness witness E for its carrier, where all? is recovered from E and ≟ from S's decidable _≈_. The existing Fin n checkers then fall out by instantiating S := ≡-decSetoid and E := Fin's all?.
Notes¶
- Keep the concrete
Fin nversions (they are what the finite examples use and they reduce well forfrom-yes); the generalized versions would sit alongside, with theFinones recovered as an instance. - This is exploratory and tied to M9-1; it does not block any current milestone.
Spun off from review discussion on #356.
Issue M4-16: Relocate the reduct development from Classical/ to Setoid/ (#403, closed)¶
Labels: milestone-4-style
Follow-up from the review of #402 (M4-5g). The notion of reduct — and the variety-level results built on it — is universal algebra: it quantifies over arbitrary signatures and signature morphisms. It is not classical algebra, where each theory studies one fixed kind of structure (groups, rings, fields) and reducts play little role. So the development belongs in Setoid/ (the universal-algebra foundation), not Classical/.
The current placement under Classical/ is genealogical, not principled. reduct was introduced in ADR-002 §5 as the engine for the classical forgetful projections (monoid→semigroup, group→monoid), so it was born in Classical.Structures; ADR-006 then kept it there ("stays in its current home") and rationalized a "Setoid.* → Classical.* would be a cycle" rule around it.
That rule is circular: the cycle exists only because reduct sits in Classical/. reduct imports only Overture.* and Setoid.Algebras.Basic — nothing from Classical/ — so the whole reduct chain can move down to Setoid/ with no cycle. Doing so also reunifies the M4-5 functorial layer, most of which (Overture.Signatures.Morphisms, Setoid.Signatures.Functor, the Setoid.Categories.* vocabulary, Overture.Terms.Translation, Setoid.Terms.*) already lives in Setoid/ / Overture/; only the reduct-touching modules were stranded in Classical/.
Scope¶
Classical.Structures.Reduct→Setoid.Algebras.Reduct(reduct,reductBy,reduct-id,reduct-∘).Classical.Categories.Reduct→Setoid.Categories.Reduct(reductF).Classical.Varieties.Invariance→Setoid.Varieties.Invariance(reduct-interp,⊧-reduct,⊧-expand).Classical.Varieties.Reducts→Setoid.Varieties.Reducts(the M4-5g module from #402; folded in when the PRs rebase — see below). The now-emptyClassical/Varieties/directory is removed.- Amend ADR-006 to reverse the "reduct stays in
Classical/" placement decision and retire the cycle rationale. - Import sweep of all consumers (
Classical.Structures.{Monoid,Group,Lattice,Ring},Classical.Categories.{AdjoinUnit,Forgetful}) and prose links (Setoid.Terms.*,Overture.Terms.Translation,Overture.Signatures.Morphisms).
Note: the moved modules are inherently two-signature, so they do not fit the single-{𝑆} umbrellas (Setoid.Algebras, Setoid.Varieties); they remain directory-resident and imported directly, as they already are.
Stays in Classical/¶
Classical.Categories.AdjoinUnitandClassical.Categories.Forgetfulare genuinely structure-specific (adjoin-a-unit to a semigroup;monoid→semigroup), so they remain — they importreductF/⊧-reductfrom the newSetoid/homes.
Interaction with #402¶
402 adds Classical.Varieties.Reducts. Whichever of #402 / this PR merges first, the other rebases. Recommended order: #402 first (so its active review is not disrupted by a path change), after which this PR folds in the Reducts → Setoid.Varieties.Reducts move.¶
Acceptance¶
nix develop --command make checkpasses (whole library).
Issue M4-17: style improvements and general clean up of Setoid modules (#434, closed)¶
Labels: milestone-4-style
Description¶
Apply new style conventions uniformly across the Setoid tree.
- clean up syntax/code-style, e.g., using dot patterns, fewer parens, etc.;
- change from one- to two- space indentation convention;
- maybe add more prose describing what the theorems say/mean.
- remove unused imports (rerun "remove unused imports" script)
Acceptance Criteria¶
- no violations of style conventions laid out in the STYLE_GUIDE doc
- any style conventions followed uniformly across modules are documented in STYLE_GUIDE
- any changes in style conventions are reflected in (updates to) the STYLE_GUIDE
Issue M4-18: Move Demos under Examples (#436, closed)¶
Labels: milestone-4-style
(no description on GitHub)
Issue M4-19: Clean up imports post-sweep (#477, closed)¶
Labels:
After the sweep that removed the signature parameter from many module definitions, the line
open import Overture using (𝓞 ; 𝓥 ; Signature ; 𝑆 )
still appears outside the start of the module, which is unnecessary when there's no top-level module parameter. We can now move the import of Overture inside with the other imports, consistent with the repo-wide style convention.
Issue M4-20: Validate kramdown attribute-span classes against Agda's own classification (#553)¶
Labels: documentation, milestone-4-style, ci
The gap¶
Every Agda name in the rendered corpus is marked up with a kramdown attribute span, `Algebra`{.AgdaRecord}, and attr_list turns the class into the CSS class that colours it. mkdocs.yml calls attr_list "THE load-bearing one" for exactly this reason.
Nothing checks that the class is the right one. check_links.py validates reference-style links, docstring_audit.py validates prose coverage, and neither looks at span classes. A span whose class disagrees with what Agda thinks the name is renders with the wrong highlighting, and no gate notices.
This surfaced in review on #552, where Copilot caught `Equivalence`{.AgdaRecord} — Equivalence A {ρ} = Σ[ r ∈ BinaryRel A ρ ] IsEquivalence r is a Σ-type alias, so a function, not a record. Looking for siblings found four more.
Four confirmed defects on master¶
| file | span | actually |
|---|---|---|
Classical/Structures/Lattice/Parachute.lagda.md (4 occurrences: 42, 65, 272, 594) |
`_≤ᵖ_`{.AgdaFunction} |
data _≤ᵖ_ : P → P → Type (α ⊔ ρ) at :261 |
Examples/Setoid/HSPCommutativeMonoid.lagda.md:101 |
`𝒦₀`{.AgdaFunction} |
data 𝒦₀ : Pred (Algebra 0ℓ 0ℓ) 1ℓ at :78 |
FLRP/Problem.lagda.md:121 |
`Lattice-Order`{.AgdaRecord} |
module Lattice-Order … at Classical/Properties/Lattice.lagda.md:58 |
FLRP/Representable.lagda.md:149 |
`Signature`{.AgdaRecord} |
Signature 𝓞 𝓥 = Σ[ F ∈ Type 𝓞 ] (F → Type 𝓥) at Overture/Signatures.lagda.md:91 |
The last is the same error class as the Equivalence one: a Σ-bundle type alias read as a record because it behaves like one.
Scale¶
Measured over src/**/*.lagda.md: 2198 span occurrences, 990 distinct (name, class) pairs, across 11 classes. The distribution is AgdaFunction 1404, AgdaRecord 257, AgdaBound 156, AgdaInductiveConstructor 112, AgdaField 110, AgdaDatatype 79, AgdaModule 73, and single digits of AgdaGeneralizable, AgdaKeyword, AgdaPrimitiveType, AgdaSymbol.
docstring_audit.py --json already emits a kind per public definition — signature (3060), module (72), record (61), data (50), pattern (31) — so ground truth for a large fraction of spans is already computed and needs no new parser.
The naive design does not work, and this is the main finding¶
Matching a span's name against the audit's kind by name alone produces 126 hits, of which only the 4 above are real. The 122 false positives come in two shapes, and both are legitimate markup:
AgdaBound, 94 hits.`N`{.AgdaBound}inside a paragraph refers to a locally bound variable. That a top-level definition namedNexists elsewhere is irrelevant, and marking the bound occurrence.AgdaBoundis correct.AgdaField, 16 hits.`to∘from`{.AgdaField}names a record field, which is not a top-level definition at all — ADR-010 deliberately excludes fields, members and constructors from the audit's inventory — so the audit has no entry to compare against and a same-named function elsewhere produces a spurious hit.
The rest are cross-module name collisions: `Lattice`{.AgdaRecord} in Setoid/Subalgebras/CompleteLattice.lagda.md is stdlib's Relation.Binary.Lattice.Lattice, a genuine record, while Classical/Small/Structures/Lattice defines an unrelated Lattice alias. Same for Group, List, and the generalizable 𝑨.
So a useful checker needs name resolution in the scope of the file the span sits in, not a global name table. A checker without it would emit 30 false positives for every real one and be switched off within a week — which is the outcome ADR-010 already warns about for un-ratcheted gates.
Two designs that could work¶
- Ask Agda.
agda --htmlemits<a class="Agda…">spans with Agda's own classification, per file and per occurrence. Rendering the corpus once and diffing our span classes against the highlighter's is the only approach that is right by construction, including for fields, constructors and bound variables. Cost: an HTML build in CI, and a mapping from source positions to the generated anchors. - Ask
agda-mcp.resolve_nameanswers "what does this name resolve to here", scoped to a file, with provenance. That is exactly the missing ingredient, and it handles the collisions. Cost: it is a live interaction lane, so a whole-corpus sweep is one load per file, and the server is currently single-worktree (arootMismatchguard refuses files from any other checkout).
Design 1 is the better fit for a gate; design 2 is the better fit for a one-off sweep to clear the existing backlog. They are not exclusive.
Done when¶
- A checker under
scripts/python/reports spans whose class disagrees with Agda's classification, with zero false positives on current master. - The four defects above are fixed, plus whatever the sweep adds.
- A
Makefiletarget and a CI job, followingcheck_links/docstring_audit(see thewriting-a-corpus-linterconventions), ratcheted if the backlog cannot be cleared in one pass. - Validated the way #537's audit was: against Agda's own answer, not against the checker's author's expectations.
Notes¶
- Related: #537 (the docstring audit and its ratchet), ADR-010 (which fixes what counts as a public definition, and why fields and constructors are excluded), #275 (the corpus extractor, another consumer of correct span classification).
- There is a second, cheaper unchecked-markup gap worth folding in or splitting out: dangling footnote references.
[^1]with no[^1]:definition renders as literal text and passes every gate. Two exist on master, inOverture/Basic.lagda.mdandClassical/Structures/Group/Complexes.lagda.md. That one is a few lines of regex and needs no Agda at all.
---¶
Milestone 5 — Cubical track¶
Issue M5-1: Cubical track — Cubical/Algebras/Basic with SIP and Monoid port (#270)¶
Labels: milestone-5-cubical
Description¶
Cubical Agda is the canonical long-term target for this library. This issue establishes the path: port the core algebra types, prove the structure identity principle (SIP), and demonstrate end-to-end workflow by porting Monoid from the Setoid-based Classical layer to a Cubical counterpart. The ultimate goal is for Cubical to become the default development track in version 3.0, with Setoid/ moving to Legacy.
Design implication for M3: the Classical layer must be designed so that the Setoid-to-Cubical port is mechanical — equations stated purely in terms of the Algebra record's Domain equivalence, no Setoid-specific gadgets in the definitions of classical structures themselves.
Tasks¶
-
Cubical/Algebras/Basic.agda: cubical counterpart ofSetoid.Algebras.Basic. Carrier is a Type; equality is the path type. -
Cubical/Algebras/SIP.agda: structure identity principle. Port or adapt from thecubicalor1Lablibrary. - Prove:
≅as defined for Cubical algebras is equivalent to path equality (the central "transport does what we want" result). - End-to-end port: take
Classical/Structures/Monoid.agdafrom the Setoid-based version (post M3-4) and produce the Cubical analog. Verify that equations transport by substitution alone. - Write
docs/adr/003-cubical-canonical-target.mdexplicitly planning the 3.0 transition and the criteria for promoting Cubical from experimental to canonical.
Acceptance criteria¶
-
Cubical/Algebras/Basic.agdaandSIP.agdacompile under--cubical. - The
≅-is-path theorem is proved. -
Cubical/Classical/Monoid.agdacompiles and is substitutionally derived from its Setoid analog. - ADR-003 is merged.
Issue M5-2: Monitor agda/agda-stdlib#2967 and finalize cubical-port flag strategy (#279)¶
Labels: agda-stdlib, milestone-5-cubical, stdlib-bridge, cubical, blocked-upstream
Context¶
The agda-stdlib maintainers are considering reverting from --cubical-compatible to --without-K for stdlib v3.0. See agda/agda-stdlib#2967 (opened 2026-03-20 by @Taneb; open, under discussion).
For agda-algebras this has concrete implications:
- Type-checking speed. The Agda 2.6.3 changelog reports ~30% faster type-checking for stdlib under plain
--without-Kvs--cubical-compatible, and ~10% faster even with-WnoUnsupportedIndexedMatchenabled. Across the lifetime of agda-algebras 2.0 this is substantial. - Import firewall. Code that uses only
--without-Kcannot be imported from code that uses--cubical. If stdlib v3.0 lands on--without-K, a futuresrc/Cubical/tree that uses--cubicalcannot import stdlib at all; it would needagda-cubical(or re-derivation) for anything stdlib-shaped. The converse direction (--cubical-compatibleimporting--without-K) is fine. - Warning noise. Under stdlib 2.3 we currently face
UnsupportedIndexedMatchwarnings on many of our own pattern-matching definitions. Either we live with the noise or suppress with-WnoUnsupportedIndexedMatch. A stdlib 3.0 revert makes this go away for stdlib's types but not for agda-algebras-internal definitions, unless we also switch our code to--without-K.
Tasks¶
- Watch agda/agda-stdlib#2967. Track the discussion; note the final decision (reverted as proposed, compromise, or
--without-K-with-opt-in). - Benchmark
--cubical-compatible→--without-Kon our own code. Branch experiment: add{-# OPTIONS --without-K --exact-split --safe #-}pragmas acrossSetoid/andClassical/, measuremake checkwall-clock delta. This is decidable today, independent of upstream. - Decide and document the
src/Cubical/→ agda-cubical strategy. Write up indocs/FLAGS.md(new file) so future contributors understand the firewall and why. The current best guess:Setoid/andClassical/remain--cubical-compatible(or move to--without-Kafter benchmark);Cubical/uses--cubical, importsagda-cubicalinstead of stdlib, and re-derives / imports-from-agda-cubical whatever stdlib types it needs. - (Deferred) Prepare comment for agda/agda-stdlib#2967. agda-algebras is a non-trivial downstream with stated cubical ambitions; the maintainers benefit from knowing our position. Hold until we have hands-on experience with agda-cubical in
src/Cubical/(see M5) — the comment should be factual ("here is what this PR means for us in practice"), not advocacy.
Relation to other milestones¶
- Informs M5 (Cubical port) fundamentally — the flag strategy for
src/Cubical/is decided here. - May inform M4 (style sweep) if a library-wide flag change lands.
- Does not block M2 or M3.
Non-goals¶
- Not blocking any other milestone; this is a monitoring issue.
- Not changing agda-algebras flags in response to a not-yet-merged upstream PR; any change lands via a separate, sweep-style PR when the decision is made.
---¶
Milestone 6 — Toward the Finite Lattice Representation Problem¶
Issue M6-1: Con(A) as a complete lattice (#271, closed)¶
Labels: milestone-6-flrp
Description¶
The current Setoid.Algebras.Congruences defines congruences but does not organize them as a lattice. For the FLRP, commutator theory, and subdirect product theorems, Con 𝑨 as a complete lattice is foundational infrastructure. Likely requires a congruence-generation theorem as a subsidiary result.
Tasks¶
- Define
Con 𝑨as a type (may exist already; promote to a first-class lattice object). - Define the partial order
_≤_(containment). - Define meet:
θ ∧ φ = θ ∩ φ. - Define join:
θ ∨ φ = Cg(θ ∪ φ)(congruence generated by union). -
Con-Lattice : (𝑨 : Algebra α ρ) → Lattice _ _. -
Con-CompleteLatticewith infinite meets and joins. - Zero and total congruences as
0ᴬand1ᴬ. - Subsidiary: congruence-generation theorem.
Acceptance criteria¶
-
Con-Lattice 𝑨type-checks and satisfies the Lattice axioms. - Infinite meets and joins are proved.
- At least one small worked example (e.g.
Conof a 2-element algebra).
Issue M6-2: Subdirect products and subdirectly irreducible algebras (#272, closed)¶
Labels: milestone-6-flrp
Description¶
Subdirect products and subdirect irreducibility are foundational for both the FLRP and for general universal-algebraic theorems (e.g. Birkhoff's subdirect representation theorem).
Tasks¶
-
SubdirectProduct/ subdirect embedding — landed asIsSubdirectEmbedding/SubdirectEmbedding(Setoid.Subalgebras.Subdirect): an injective hom into⨅ 𝒜whose every coordinate projection is surjective (the standard relational presentation of "a subalgebra of⨅ 𝒜meeting every factor", rather than a separately-constructed algebra). -
IsSubdirectlyIrreducible : Algebra α ρ → Type _— landed (Setoid.Congruences.Monolith), defined asNontrivial × HasMonolith. - Birkhoff's subdirect representation theorem — the choice-free core is proved (
SIRep→Representable: a separating SI-family of congruences yields a subdirect embedding into a product of SI algebras);Birkhoff-subdirectproves the full statement relative to an explicit choice principle (SubdirectSIRepexistence), the Zorn step isolated as a module parameter rather than postulated. - SI characterization via monolithic congruences —
monolith⇒cmi(a monolith makes0ᴬcompletely meet-irreducible) and the binary instancemonolith⇒∧-irreducible(0ᴬis meet-irreducible); plusmonolith-unique.
Acceptance criteria¶
- Subdirect product construction type-checks —
Setoid.Subalgebras.Subdirecttype-checks undermake check. - Birkhoff's subdirect representation theorem is proved — constructive core in full; the choice-dependent existence is an explicit module parameter (mirrors M6-3's handling of choice-dependent theorems). See the design note.
- SI characterization is proved — the forward direction (monolith ⟹ completely meet-irreducible) is proved constructively; the converse is predicativity-blocked and recorded as a follow-up.
Status — first pass (PR #418)¶
The constructive core of subdirect representation theory landed in two modules:
Setoid.Congruences.Monolith—Nontrivial/Trivial,Nonzerocongruences, the infinitary meet⋂,IsMonolith/HasMonolith/monolith-unique,IsSubdirectlyIrreducible, and the characterizationmonolith⇒cmi/monolith⇒∧-irreducible.Setoid.Subalgebras.Subdirect—⨅-proj,coord,IsSubdirectEmbedding/SubdirectEmbedding/subdirect→≤; the bridgeseparating→SubdirectEmbedding(withnatmap-injective/natmap-separates, and arefl-checkedIsInjective (proj₁ natmap) ≡ Separates, showing injectivity is definitionally the separation hypothesis "the meet is the diagonal"); andBirkhoff-subdirect, the subdirect representation theorem relative to the choice principleSubdirectSIRep.
The choice/Zorn decision (option (a): explicit module parameter), the constructive-¬¬ reason the parameter is a separating SI-family rather than per-pair maximal congruences, the predicativity wall blocking the cmi-⟹-monolith converse, and the level conventions are recorded in docs/notes/m6-2-subdirect.md. Follow-ups: the constructive finite case (option (b), discharging the parameter by search when ≈ is decidable); the impredicative converse; and linking SI to the absence of a nontrivial subdirect decomposition.
Issue M6-3: Basic Maltsev conditions (CD, CM, CP) (#273, closed)¶
Labels: milestone-6-flrp, design-discussion
Description¶
Maltsev conditions characterize varieties by the existence of terms with specific properties. The three most basic are congruence distributivity (CD), congruence modularity (CM), and congruence permutability (CP). For the FLRP, congruence modularity is particularly relevant because modular congruence lattices are a natural testing ground for representation questions.
Design discussion: how to encode Maltsev conditions uniformly? Options include (a) a record bundling a term and its identities; (b) an inductive type of schemes. Lift from Taylor 1977 where possible.
Tasks¶
-
HasMaltsevTerm : Variety → Term → Type— landed as the interpretation predicateHasMaltsevTerm ℰ = Th-Maltsev ≼ ℰ(Setoid.Varieties.Maltsev). - Specific Maltsev terms: Jónsson terms (CD), Day terms (CM), Maltsev operation (CP) —
Th-Maltsev,Th-Jonsson n,Th-Day n, withHasMaltsevTerm/HasJonssonTerms n/HasDayTerms n(Setoid.Varieties.Maltsev). - Jónsson's theorem: a variety is CD iff Jónsson terms exist — stated (
Jonsson-Statement); proof tracked in #412 (forward) and #413 (converse). - CP iff a Maltsev term exists — forward direction
MaltsevTerm⇒CP/maltsev⇒CP(M6-3, #409); converseCP⇒maltsev(Setoid.Varieties.Maltsev.Permutability, M6-5, #411) inhabitingCP⇒maltsev-Statement, built on the free-algebra bridge (Setoid.Varieties.FreeSubstitution, M6-4, #410). - Day's theorem for CM — stated (
Day-Statement); proof tracked in #412 (forward) and #413 (converse).
Acceptance criteria¶
- At least CP's Maltsev-term characterization is proved —
MaltsevTerm⇒CP/maltsev⇒CPinSetoid.Varieties.Maltsev.Permutability(the concrete "term ⟹ permutable" direction). - Jónsson's theorem and Day's theorem are either proved or have a clear stub indicating what remains — both stated as checked, uninhabited
Types, with construction plans indocs/notes/m6-3-maltsev-conditions.md.
Status — first pass (PR #409)¶
The CP track landed in PR #409:
Setoid.Congruences.Permutability— relation compositionθ ∘ φ, thePermutespredicate (θ ∘ φ ⊆ φ ∘ θ), andCongruencePermutable.Setoid.Congruences.Properties—CongruenceDistributiveandCongruenceModular.Setoid.Varieties.Maltsev.{Basic,Permutability,Distributivity,Modularity}(split from the originalMaltsevConditionsmodule in #428, re-exported bySetoid.Varieties.Maltsev) —term-compatible; the forward Maltsev theoremMaltsevTerm⇒CP/maltsev⇒CP; the Jónsson and Day term theories; and the deferred theorems (CP⇒maltsev-Statement,Jonsson-Statement,Day-Statement) as checkedTypestatements.- Design note:
docs/notes/m6-3-maltsev-conditions.md.
The chosen encoding is the interpretation Th-X ≼ ℰ (preferred over the issue's options (a) record and (b) inductive scheme; see the note).
Deferred proofs are tracked in successor issues: #410 ([M6-4] free-algebra Cg↔derivability bridge — landed, Setoid.Varieties.FreeSubstitution), #411 ([M6-5] CP converse — landed, CP⇒maltsev in Setoid.Varieties.Maltsev.Permutability), #412 ([M6-6] forward Jónsson/Day — landed), #413 ([M6-7] converse Jónsson/Day — landed). See the design note docs/notes/m6-4-free-bridge.md for #410 / #411.
Issue M6-4: Free-algebra congruence/derivability bridge (infrastructure for the Maltsev-condition converses) (#410, closed)¶
Labels: milestone-6-flrp
Description¶
The converse directions of the basic Maltsev conditions (a lattice property of Con 𝑨 ⟹ the existence of terms) are all proved the same way: read equational identities off the congruences of the relatively free algebra 𝔽[ X ]. This issue builds the reusable bridge that all of them need — between the generated congruence Cg R on 𝔽[ X ] and derivability _⊢_▹_≈_ — so the converse issues ([M6-5], [M6-7]) can consume it rather than each re-deriving it.
It is the single biggest lever identified in the M6-3 design note: built once, it unlocks the CP, CD, and CM converses.
Background¶
- M6-3 (#273, PR #409) landed the CP layer and the forward Maltsev theorem, and stated the deferred converses as checked, uninhabited
Types (CP⇒maltsev-Statement,Jonsson-Statement,Day-Statement). - Construction plan and rationale:
docs/notes/m6-3-maltsev-conditions.md, § "The deferred theorems and their construction plans".
Tasks¶
- Substitution-induced homomorphism
𝔽[ X ] → 𝔽[ Y ]from a map of variables (X → Term Y, and the special caseX → Y), with the proof that it is a homomorphism — its action on a term is substitution_[_], which commutes withnodeby definition. - Package the kernel of a homomorphism as a
Con(compatibility isHomKerCompinSetoid.Homomorphisms.Kernels; add the equivalence andreflexivefields). - The bridge lemma: for a relation
Ron𝔽[ X ]cut out by finitely many identified pairs,Cg R ⊆ ker hfor any homhthat collapses those pairs (immediate fromCg-least); hence membership in a principal congruenceCg {(s , t)}yields a derivable equation in the quotient. - The impedance shims between the
Idx → Term × Termtheory shape used by_≼_and theI → Eqshape used by_⊢_▹_≈_/𝔽[_], in both directions, so a witness term extracted in𝔽can be packaged as anInterpretationand discharged via⊧-interp+ soundness.
Dependencies¶
- None beyond what M6-3 (#273, PR #409) landed. This is the prerequisite for [M6-5] and [M6-7].
Acceptance criteria¶
- The bridge lemmas type-check under
--cubical-compatible --exact-split --safe. - At least one smoke-test consumer: recover a single derivable identity from a principal-congruence membership on
𝔽[ X ].
References¶
Setoid.Varieties.SoundAndComplete(𝔽[_],satisfies, soundness/completeness);Setoid.Congruences.Generation(Cg,Cg-least);Setoid.Homomorphisms.Kernels(HomKerComp);Setoid.Varieties.Interpretation(⊧-interp).- Burris and Sankappanavar, A Course in Universal Algebra, Ch. II.
Status — landed¶
The bridge originally landed as Setoid.Varieties.FreeBridge, dissolved in the #428 cleanup; its API now lives in Setoid.Varieties.FreeSubstitution: subhom / renhom (the substitution-induced hom out of 𝔽[ X ], a homomorphism by refl), cg-pair→⊢ / cg-pairs→⊢ (the bridge lemma, one line via Cg-least), and the smoke test recover / recover-gen / recover-swap. Its dependencies were distributed to Setoid.Homomorphisms.Properties (Cg⊆ker, and the re-exported kernel-as-Con kercon), Setoid.Congruences.Generation (the principal relation ❴_,_❵), and Setoid.Varieties.SoundAndComplete (the toEq shim — the two satisfaction predicates _⊨ₑ_ / _⊨_ coincide definitionally, so no conversion function is needed). The term-level companion graft≐[] (identifying _✦_'s graft with _[_]) lives with the other laws of graft in Setoid.Terms.Interpretation. Design note: docs/notes/m6-4-free-bridge.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MvPrLTCxKjFgsnTMK8j2qZ
Issue M6-5: Converse of Maltsev's theorem: congruence-permutable ⟹ Maltsev term (#411, closed)¶
Labels: milestone-6-flrp
Description¶
Complete the congruence-permutability characterization by proving the converse of Maltsev's theorem: a congruence-permutable variety has a Maltsev term. Concretely, inhabit CP⇒maltsev-Statement in Setoid.Varieties.Maltsev.Permutability. M6-3 (#273, PR #409) proved the forward direction (MaltsevTerm⇒CP); together they give the iff.
Background¶
Construction (Burris–Sankappanavar, Thm. 12.2), detailed in docs/notes/m6-3-maltsev-conditions.md:
- Work in
𝔽[ Fin 3 ], the relatively free algebra on three generatorsx , y , z; it is a model ofℰ(satisfies), hence congruence-permutable by hypothesis. - Take the principal congruences
θ = Cg(x , y)andφ = Cg(y , z). Fromx θ yandy φ zwe get(x , z) ∈ θ ∘ φ; permutability gives(x , z) ∈ φ ∘ θ, i.e. a witnesswwithx φ wandw θ z. - Since the carrier of
𝔽isTerm (Fin 3),wis literally a termM(x , y , z). Translatingx φ wandw θ zthrough the collapsing-substitution homomorphisms (z ↦ y, resp.x ↦ y) yieldsM(x , y , y) ≈ xandM(x , x , y) ≈ y— the two Maltsev identities. - Package
Mas the interpretationTh-Maltsev ≼ ℰand discharge via⊧-interp+ soundness.
Note: #273's text says "the free algebra on two generators"; the standard construction is on three generators x , y , z, since the Maltsev term has three variables.
Tasks¶
- Build the principal congruences and the
θ ∘ φmembership in𝔽[ Fin 3 ]; apply the CP hypothesis. - Extract the witness
was a term and translate both memberships to the two identities via the [M6-4] bridge (#410). - Assemble the interpretation and inhabit
CP⇒maltsev-Statement.
Dependencies¶
- [M6-4] (#410) — the free-algebra congruence/derivability bridge. This is the smallest client of that bridge and a good first validation of it.
Acceptance criteria¶
CP⇒maltsev-Statementis inhabited; withmaltsev⇒CP, congruence permutability is characterized by the Maltsev term (a complete iff).
References¶
- A. I. Mal'cev, On the general theory of algebraic systems (Russian), Mat. Sb. (N.S.) 35(77) (1954), 3–20; Engl. transl., Amer. Math. Soc. Transl. (2) 27 (1963), 125–142. Math-Net.Ru.
- Burris and Sankappanavar, A Course in Universal Algebra, Thm. II.12.2.
Status — landed¶
CP⇒maltsev (in Setoid.Varieties.Maltsev.Permutability) inhabits CP⇒maltsev-Statement at the levels of 𝔽[ Fin 3 ], for theories with variables X : Type 0ℓ (forced by the single-level free-algebra interface; no restriction for finitary theories). The collapsing substitutions are chosen to coincide with the _✦_ position maps, so the bridge output is definitionally the interpreted Maltsev identity up to one graft≐[] step. With maltsev⇒CP, congruence permutability is now a complete iff. Design note: docs/notes/m6-4-free-bridge.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MvPrLTCxKjFgsnTMK8j2qZ
Issue M6-6: Forward Jónsson/Day: Jónsson terms ⟹ CD and Day terms ⟹ CM (#412, closed)¶
Labels: enhancement, milestone-6-flrp
Description¶
Prove the "terms ⟹ lattice property" halves of Jónsson's and Day's theorems: a variety with Jónsson terms is congruence-distributive, and a variety with Day terms is congruence-modular. These are the second projections of Jonsson-Statement and Day-Statement in the Setoid.Varieties.Maltsev subtree (Jonsson-Statement in Maltsev.Distributivity, Day-Statement in Maltsev.Modularity): with P ⇔ Q = (P → Q) × (Q → P) and Jonsson-Statement = CongruenceDistributiveVariety ⇔ (Σ n, HasJonssonTerms n), the term ⟹ CD direction is proj₂ (Q → P), not the first projection. (The original text said "first projections"; corrected here.)
These halves are independent of [M6-4] (#410): they use the chain terms available on every algebra via the interpretation, plus term-compatible and an induction over the join.
Status: COMPLETE (forward Jónsson in PR #428; forward Day in PR #442)¶
Forward Jónsson: DONE — including the featured finitary theorem, unconditionally.
- The former monolithic
MaltsevConditionsmodule was split intoSetoid.Varieties.Maltsev.{Basic,Permutability,Distributivity,Modularity}(re-exported by theSetoid.Varieties.Maltsevumbrella); the Jónsson development lives inMaltsev.Distributivity. - Generalized the curried-term extraction from one ternary symbol to the
Fin (n+1)Jónsson chain (d𝑩/eval-d/d-fst/d-lst/d-mid/d-compat). - The two-part staircase: the horizontal lemma (induction on the chain) and the vertical induction over the rungs (
Data.Fin.Induction.<-weakInduction, whoseinject₁ i → suc istep lines up with the parity-split forkd-fork i). jonsson⇒chainDistributive— the forward inclusionθ ∧ (φ ∨ ψ) ⊆ (θ∧φ) ∨ (θ∧ψ)along every chain, fully general (no finiteness).jonsson⇒CongruenceDistributive/jonsson⇒CongruenceDistributiveVariety— the literalCongruenceDistributive/CongruenceDistributiveVariety(theproj₂direction ofJonsson-Statement), modulo the one isolated hypothesisJoinIsChain.jonsson-finitary⇒CongruenceDistributiveVariety— the featured theorem: a variety over a finitary signature with Jónsson terms is congruence-distributive, with no residual side condition. This is the form a working algebraist applies; universal algebra in practice means finitary algebras.
The Gen-vs-chain obstruction: named once, then discharged for finitary signatures. The library's join is Cg(φ ∪ ψ) = Gen(φ ∪ ψ), the inductively-generated congruence whose comp constructor closes it under the basic operations (necessary and correct for infinitary signatures, whose arities are arbitrary types). The Jónsson-term "sandwich" relation dᵢ(a,u,b) γ dᵢ(a,v,b) is provably not closed under comp, so a direct Gen-induction cannot carry the staircase, and for an infinitary signature the join strictly exceeds the finite-chain closure. The forward theorem is therefore proved against Chain in full generality, the lone missing step Gen(φ ∪ ψ) ⊆ Chain is isolated as the explicit hypothesis JoinIsChain, and that hypothesis is then discharged for finitary signatures in the module Setoid.Congruences.ChainJoin (finitary⇒JoinIsChain): Chain 𝑩 (φ ∪ᵣ ψ) is shown to be a congruence (operation-closed via the one-coordinate-at-a-time fold chain-op over a finite-arity enumeration Finitary 𝑆), hence contains the generated join by Cg-least. The Examples.Setoid.FinitarySignatures module shows the Finitary witness is a hoop-free one-liner (λ _ → _ , ↔-id _).
Forward Day: DONE (PR #442) — by a genuinely different ladder, not a mirror. As predicted, Day's mᵢ(x,y,y,x) ≈ x pinning requires the two middle arguments equal, so the even-fork column mᵢ(a,a,b,b) is not ψ-pinnable and the Jónsson two-column staircase does not transfer. The construction that landed is Day 1969 in the streamlined form of Freese–McKenzie (Commutator Theory for Congruence Modular Varieties, Thm 2.2 and Lemma 2.3), inlined into a single chain-level induction in Setoid.Varieties.Maltsev.Modularity:
m-collect(FM Lemma 2.3), for an arbitrary congruenceμ: givenb μ d, rung-wiseμ-relations between the ladder columnsmᵢ(a,a,c,c)andmᵢ(a,b,d,c)collect intoa μ c. The unpinnable even-fork column is never pinned — it is carried by the hypothesis pair, which is the two-dimensional aspect of Day's construction.Day⇒chainModular— the modular inclusion(θ ∨ ϕ) ∧ ψ ⊆ θ ∨ (ϕ ∧ ψ)(forθ ⊆ ψ) along every θ/ϕ-chain, fully general (no finiteness): an outer induction on the number of ϕ-steps whose decrease comes from fusing the two flanking ϕ-steps of the heada ϕ t₁ θ t₂ ϕ t₃ ⋯into a single two-slotm-compatmove, with the remaining chain pushed through the third slot ofmᵢ(m-push) and the induction hypothesis applied to the ψ-railed pair(mᵢ(a,t₁,t₂,c), mᵢ(a,a,c,c)).Day⇒CongruenceModular(moduloJoinIsChain, applied once, to the hypothesis join),Day+finjoin⇒CM, and the unconditional finitaryDay⇒CM.Day-theorem— the complete iff, assembled with the M6-7 converseCM⇒Day(#413, PR #440), which now takes itsFinitarywitness as an explicit argument, mirroringCD⇒jonsson.
With this, all three classical Maltsev-condition theorems (Maltsev/CP, Jónsson/CD, Day/CM) are proved in both directions.
Remaining tasks¶
None — this issue is complete once PR #442 merges.
Dependencies¶
- None beyond M6-3 (#273, PR #409): reuses
term-compatible, the curried-extraction pattern, and the congruence lattice (Setoid.Congruences.{Lattice,Generation,Properties}). Independent of [M6-4] (#410).
Acceptance criteria¶
- Forward Jónsson type-checks under
--safe; the term ⟹ CD direction of Jónsson's theorem is done, and the finitary version is unconditional. ✅ (PR #428;make checkpasses.) - Forward Day type-checks under
--safe; the term ⟹ CM direction of Day's theorem is done, the finitary version is unconditional, andDay-theoremassembles the complete iff. ✅ (PR #442;make checkpasses.)
Notes¶
- Difficulty: the Jónsson half was moderate as expected; the realized work surfaced two findings — the
Gen-vs-chain (infinitarycomp) obstruction, discharged for finitary signatures, and that Day is not a mechanical mirror of Jónsson. The Day half then required the genuinely two-dimensional FM Lemma 2.3 ladder, with a ϕ-count measure whose decrease is a two-steps-into-one fusion. All of this is recorded indocs/notes/m6-6-forward-jonsson-day.md("Why Day is not a mirror — and the ladder that works").
References¶
- B. Jónsson, Algebras whose congruence lattices are distributive, Math. Scand. 21 (1967), 110–121. doi:10.7146/math.scand.a-10850 (open access).
- A. Day, A characterization of modularity for congruence lattices of algebras, Canad. Math. Bull. 12 (1969), 167–173. doi:10.4153/CMB-1969-016-6.
- R. Freese and R. McKenzie, Commutator Theory for Congruence Modular Varieties, LMS Lecture Note Series 125, Cambridge University Press (1987), Thm 2.2 and Lemma 2.3. Free online edition.
- Burris and Sankappanavar, A Course in Universal Algebra, Thms. II.12.6 (Jónsson) and II.12.4 (Day).
🤖 Generated with Claude Code
https://claude.ai/code/session_011crz6XaiE4uecELazSkJFY
Issue M6-7: Converse Jónsson/Day: CD ⟹ Jónsson terms and CM ⟹ Day terms (#413, closed)¶
Labels: enhancement, milestone-6-flrp, research-exploratory
Description¶
Complete Jónsson's and Day's theorems with the hard "lattice property ⟹ terms" directions: a congruence-distributive variety has Jónsson terms, and a congruence-modular variety has Day terms. These inhabit the converse projections of Jonsson-Statement and Day-Statement (with the orientation P ⇔ Q = (P → Q) × (Q → P) fixed in #412, the CD ⟹ terms direction is the first projection; the original text said "second"), turning both into complete iffs. Following the #428 module split, the statements live in Setoid.Varieties.Maltsev.{Distributivity,Modularity}.
This is the research-grade end of the M6-3 track. Beyond the [M6-4] (#410) bridge, it requires extracting the chain length n and the terms dᵢ / mᵢ from the inductive derivation witnessing a join membership — the source of the Σ[ n ∈ ℕ ] in the statements, and the part with no off-the-shelf analogue in the library.
Background¶
Construction (Burris–Sankappanavar, Thms. 12.6 and 12.4), sketched in docs/notes/m6-3-maltsev-conditions.md:
- Work in
𝔽[ Fin 3 ](Jónsson) /𝔽[ Fin 4 ](Day); set up the principal congruences whose distributive / modular identity forces the chain. - Extract
n : ℕand the parity-correct chain of terms from theGenderivation witnessing the relevant join membership. - Package the chain as an interpretation and discharge via
⊧-interp+ soundness (through the [M6-4] bridge).
Status (PRs #438, #440): COMPLETE¶
Converse Jónsson: DONE — and Jónsson's theorem is a complete iff for finitary signatures. CD⇒jonsson inhabits the CD ⟹ terms direction of Jonsson-Statement, and jonsson-theorem assembles both halves, all in Setoid.Varieties.Maltsev.Distributivity, next to the statement and the M6-6 forward half.
- The crux, realized. The chain-length extraction is
finitary⇒JoinIsChain(M6-6,Setoid.Congruences.ChainJoin) applied in𝔽[ Fin 3 ]to the membership(x , z) ∈ (θ∧φ) ∨ (θ∧ψ)that distributivity produces fromθ = Cg ❴x,z❵,φ = Cg ❴x,y❵,ψ = Cg ❴y,z❵; the chain length is theΣ[ n ∈ ℕ ], and the chain elements — terms, since the carrier of𝔽[ Fin 3 ]isTerm (Fin 3)— are the Jónsson termsd₀ … dₙ. - The one genuinely new piece is parity normalization (
ParityChain/chain→parity): the chain's steps arrive in arbitrary tag order, whileTh-Jonsson's forks demand(θ∧φ)-steps at even and(θ∧ψ)-steps at odd positions. Mismatches are padded with congruence-reflexivity steps;pconsswaps the two relations in its tail, soeven? (suc k) = not (even? k)keeps the parity bookkeeping definitional (no numeric lemmas). - Parity cross-check (third task, Jónsson half): confirmed. Even forks collapse
y ↦ x(the φ-pair), odd forks collapsez ↦ y(the ψ-pair) — exactly the normalized chain's even/odd step relations, matchingTh-Jonsson'seven?split. - Everything else is the
CP⇒maltsevpattern (M6-4/M6-5): the bridgecg-pair→⊢per identity family, collapsing substitutions chosen to be theI ✦position maps (so every collapse condition isrefland onlygraft≐[]shims remain), and⊧-interp+soundto discharge satisfaction in an arbitrary model; the θ-tie of every chain element toxis a<-weakInductionover the rungs. - The
Finitaryhypothesis is inherited from the M6-6 chain collapse, so both directions ofjonsson-theoremcarry the same one-liner witness; the levels are those of the free-algebra construction (𝔽[ Fin 3 ] : Algebra (lsuc 0ℓ) (ι ⊔ lsuc 0ℓ), variable typeX : Type 0ℓ), the same instantiation asCP⇒maltsev. - Design note:
docs/notes/m6-7-reverse-jonsson.md; roadmap updated indocs/GITHUB_PROJECT.md.
Converse Day: DONE (PR #440) — this completes the issue. CM⇒Day (born CM⇒day; renamed, and given an explicit Finitary 𝑆 argument mirroring CD⇒jonsson, in PR #442) inhabits the CM ⟹ terms direction of Day-Statement in Setoid.Varieties.Maltsev.Modularity, the planned mechanical mirror of CD⇒jonsson over 𝔽[ Fin 4 ] (Burris–Sankappanavar II.12.4).
- The congruences are
θ = Cg ❴y,z❵,φ = Cg ❴x,y❵ ∨ Cg ❴z,u❵,ψ = Cg ❴x,u❵ ∨ Cg ❴y,z❵, withθ ⊆ ψthe modular side condition;(x , u)lies in(θ ∨ φ) ∧ ψ, and the modular law read right to left moves it intoθ ∨ (φ ∧ ψ), whencefinitary⇒JoinIsChainextracts the Day chain. - Day's
φandψare joins of two principal congruences, so their collapsing substitutions must kill two generator pairs at once: the two-pair bridgecg-pairs→⊢(added toSetoid.Varieties.FreeSubstitution, next tocg-pair→⊢) is the one new piece of machinery — a single⊎-split over the sameCg⊆kerargument. - Parity cross-check (third task, Day half): confirmed. The modular join carries its θ-steps in the first
∪ᵣtag whileTh-Day's even forks are the φ-collapses, so the normalization is the off-phase passchain→parityᵒ: even forks collapsey ↦ x , z ↦ u(the two φ-pairs), odd forksz ↦ y(the θ-pair), and the middle familymᵢ(x,y,y,x) ≈ xcollapsesz ↦ y , u ↦ xvia the ψ-tie (head-linkedatψ). - Design note:
docs/notes/m6-7-reverse-day.md; roadmap updated indocs/GITHUB_PROJECT.md.
Day's forward half (terms ⟹ CM) was tracked separately on #412 and has since landed (PR #442, closing #412): Day-theorem assembles the complete iff, so Day's theorem now stands as an iff alongside jonsson-theorem, and no Day item remains open anywhere.
Tasks¶
- ~CD ⟹ Jónsson terms: extract the ternary chain
d₀ … dₙand inhabit the converse projection ofJonsson-Statement.~ ✅ PR #438 (CD⇒jonsson,jonsson-theorem). - ~CM ⟹ Day terms: extract the quaternary chain
m₀ … mₙand inhabit the converse projection ofDay-Statement.~ ✅ PR #440 (CM⇒Day,Setoid.Varieties.Maltsev.Modularity; renamed fromCM⇒dayin PR #442). - ~Confirm the extracted identities match the parity convention of
Th-Jonsson/Th-Day(cross-check the even/odd argument patterns when the proof is in hand).~ ✅ both halves (PR #438, PR #440; details in the Status section above).
Dependencies¶
- [M6-4] (#410) — the free-algebra congruence/derivability bridge.
- [M6-6] (#412) — the chain-term extraction and the forward halves (reused for the parity bookkeeping and the curried chain operations).
Acceptance criteria¶
- Both converse implications type-check under
--safe; Jónsson's and Day's theorems are complete iffs. ✅ in full: Jónsson converse PR #438 with the complete iffjonsson-theorem; Day converse PR #440; and the once re-scoped clause — Day's full iff — discharged by PR #442 on #412, which landed the forward half and assembledDay-theorem.
Notes¶
- Difficulty: hard. The derivation-length / chain extraction from an inductively-generated congruence is the crux; budget accordingly and consider landing CD ⟹ Jónsson first, with CM ⟹ Day mirroring it. (Realized as planned: reverse Jónsson landed first; the crux decomposed into the M6-6
finitary⇒JoinIsChainplus the new parity normalization, and reverse Day was the predicted mechanical mirror.) - Close-out: PR #446 reconciles the two M6-7 design notes with the post-#442 state (the
CM⇒Dayrename and the landed forward half) and closes this issue on merge.
References¶
- B. Jónsson, Algebras whose congruence lattices are distributive, Math. Scand. 21 (1967), 110–121. doi:10.7146/math.scand.a-10850.
- A. Day, A characterization of modularity for congruence lattices of algebras, Canad. Math. Bull. 12 (1969), 167–173. doi:10.4153/CMB-1969-016-6.
- S. Burris and H. P. Sankappanavar, A Course in Universal Algebra, Thms. II.12.6 (Jónsson) and II.12.4 (Day).
🤖 Generated with Claude Code
https://claude.ai/code/session_011crz6XaiE4uecELazSkJFY
Issue M6-8: Finite Birkhoff: discharge SubdirectSIRep constructively for finite algebras with decidable equality (#419, closed)¶
Labels: enhancement, milestone-6-flrp
Description¶
[M6-2] (#272, PR #418) proved the choice-free core of Birkhoff's subdirect representation theorem: the bridge separating→SubdirectEmbedding (a family of congruences whose meet is the diagonal embeds 𝑨 subdirectly into the product of its quotients) and the reduction SIRep→Representable. The full theorem Birkhoff-subdirect is stated relative to a module parameter SubdirectSIRep 𝑨 — the existence of a separating family of SI-quotient congruences — because producing it in general is a Zorn's-lemma step (a congruence maximal among those excluding a given pair), incompatible with postulate-free --safe.
For finite algebras with decidable setoid equality that parameter can be discharged constructively: the congruence lattice is finite and searchable, so for each pair a ≢ b one finds a congruence maximal among those not relating a , b by search. Such a congruence is completely meet-irreducible, hence its quotient is subdirectly irreducible (via the monolith characterization in Setoid.Congruences.Monolith), and the family over all distinct pairs separates points. This turns Birkhoff-subdirect into an unconditional theorem on finite algebras — and finiteness is exactly the FLRP setting, so this is the payoff direction.
This is option (b) of the M6-2 design note (docs/notes/m6-2-subdirect.md).
Tasks¶
- Fix the finiteness/decidability interface: a decidable setoid equality on
𝕌[ 𝑨 ]and a finiteness/enumerability witness for the relevant congruences at the working level. Decide the cleanest encoding (reuse any existingFin/Setoid-based finiteness already in the tree). - For a distinct pair
a , b, search the (finite) set of congruences not relatinga , bfor a maximal one, and prove its maximality. - Show a maximal-separating congruence is completely meet-irreducible and that its quotient is
IsSubdirectlyIrreducible. Note the subtlety the design note flags: with decidable≈the¬¬-gap that blocks the general construction disappears, so the family's meet is exactly the diagonal. - Assemble
SubdirectSIRep 𝑨(index = distinct pairs) and instantiateBirkhoff-subdirectto obtain the unconditional finite statement.
Dependencies¶
- [M6-2] (#272, PR #418) —
Setoid.Subalgebras.Subdirect(the bridge,SubdirectSIRep,Birkhoff-subdirect) andSetoid.Congruences.Monolith(SI via monolith,monolith⇒cmi).
Acceptance criteria¶
- A constructive
SubdirectSIRep 𝑨for finite algebras with decidable equality, andBirkhoff-subdirectinstantiated to an unconditional subdirect-representation theorem on that class, type-checking under--cubical-compatible --exact-split --safe.
References¶
- Burris and Sankappanavar, A Course in Universal Algebra, Thm. II.8.6 (Birkhoff's subdirect representation theorem).
- Design note:
docs/notes/m6-2-subdirect.md(option (b)).
🤖 Generated with Claude Code
https://claude.ai/code/session_01B9q9aP34sakGdPgZVaXU2s
Issue M6-9: The completely-meet-irreducible ⟹ monolith converse (needs an impredicative/resized congruence meet) (#420)¶
Labels: enhancement, milestone-6-flrp, design-discussion
Description¶
Setoid.Congruences.Monolith (from [M6-2] (#272, PR #418)) proves the useful direction of the subdirect-irreducibility characterization: a monolith makes 0ᴬ completely meet-irreducible (monolith⇒cmi, in the constructive contrapositive form "every member of a family nonzero ⟹ the meet is nonzero").
The converse — 0ᴬ completely meet-irreducible ⟹ a monolith exists — is not proved, for a predicativity reason. The natural construction takes the monolith to be μ = ⋀ { θ : Nonzero θ }, the meet of all nonzero congruences; but that family is indexed by Σ[ θ ∈ Con 𝑨 ℓ ] Nonzero θ, which lives one universe up, so the meet lands at a level ℓ′ > ℓ and is not a monolith at level ℓ. This is the same predicativity wall the complete-lattice construction meets (completeness only for ℓ₀-small families).
Tasks¶
- Decide the resolution: (i) a level-polymorphic monolith /
IsSubdirectlyIrreducibleallowing the monolith one level up; (ii) an impredicative or resized congruence meet, taken as an explicit parameter (mirroring the M6-2 choice-principle discipline, so nothing is postulated under--safe); or (iii) restrict to a setting where the nonzero congruences areℓ-small (e.g. finite, dovetailing with [M6-8]). - Prove the converse under the chosen resolution: from completely-meet-irreducible
0ᴬ(and nontriviality) construct the least nonzero congruence and showIsMonolith. - Record the assumption / level cost explicitly.
Dependencies¶
- [M6-2] (#272, PR #418) —
Setoid.Congruences.Monolith(IsMonolith,Nonzero,⋂,monolith⇒cmi).
Acceptance criteria¶
cmi ⟹ HasMonolithproved (at the appropriate level / under the stated resizing assumption), completing the SI ⟺ completely-meet-irreducible characterization, type-checking under--safe.
References¶
- Design note:
docs/notes/m6-2-subdirect.md(§ "The monolith characterization and its converse").
🤖 Generated with Claude Code
https://claude.ai/code/session_01B9q9aP34sakGdPgZVaXU2s
Issue M6-10: Subdirectly irreducible ⟺ no nontrivial subdirect decomposition (the structural characterization) (#421, closed)¶
Labels: enhancement, milestone-6-flrp
Description¶
Setoid.Congruences.Monolith (from [M6-2] (#272, PR #418)) defines subdirect irreducibility order-theoretically: IsSubdirectlyIrreducible 𝑨 = Nontrivial 𝑨 × HasMonolith 𝑨. What makes the name apt is the structural characterization: 𝑨 is subdirectly irreducible iff it has no nontrivial subdirect decomposition — i.e. in every subdirect embedding 𝑨 ↪ ⨅ 𝒜, some coordinate projection projᵢ ∘ h is an isomorphism. This issue proves that equivalence, tying Setoid.Congruences.Monolith to Setoid.Subalgebras.Subdirect.
Tasks¶
- State "no nontrivial subdirect decomposition": in every subdirect embedding
h : 𝑨 ↪ ⨅ 𝒜, some coordinate map is an isomorphism. Pick the cleanest constructive phrasing — via the kernels, a subdirect embedding corresponds to a separating familyθ(⋂ θthe diagonal), and "some projection is iso" ⟺ "someθ i ≑ 0ᴬ". - Prove monolith ⟹ structural irreducibility: if
⋂ θis the diagonal and𝑨has a monolithμ, then someθ i ≑ 0ᴬ(elseμ ⊆ θ ifor alli, soμ ⊆ ⋂ θ ≑ 0ᴬ, contradictingNonzero μ) —monolith⇒cmitransported across the kernel/subdirect correspondence. Extracting the specificiconstructively may need the index decidable/finite (coordinate with [M6-8]); otherwise state the contrapositive. - Prove the converse (structural ⟹ monolith), or document its level/choice cost if it mirrors [M6-9].
Dependencies¶
- [M6-2] (#272, PR #418) —
Setoid.Subalgebras.SubdirectandSetoid.Congruences.Monolith. - Likely interacts with [M6-8] (finite/decidable extraction) and [M6-9] (the converse's predicativity).
Acceptance criteria¶
- The equivalence (at least the constructive direction, with the converse proved or its cost documented) type-checks under
--safe, connectingIsSubdirectlyIrreducibleto subdirect decompositions.
References¶
- Burris and Sankappanavar, A Course in Universal Algebra, Def. II.8.3 and Thm. II.8.4.
- Design note:
docs/notes/m6-2-subdirect.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_01B9q9aP34sakGdPgZVaXU2s
Issue M6-11: Sub(A) as a complete lattice (next Setoid.Algebras.Lattices instance) (#373, closed)¶
Labels: milestone-6-flrp
Description¶
With the congruence lattice now in place (#271, modules Setoid.Algebras.Congruences.{Lattice,Generation,CompleteLattice} plus the general Setoid.Algebras.Lattices.CompleteLattice record), the natural companion is the subalgebra lattice: the subuniverses of a setoid algebra 𝑨, ordered by inclusion, form a complete lattice Sub 𝑨. This is the second motivating instance of the CompleteLattice record and is foundational for the FLRP (every finite lattice question is, after all, about lattices of the form Con 𝑨 / Sub 𝑨).
Most of the hard work already exists in Setoid.Subalgebras.Subuniverses:
Subuniverses 𝑨— the predicate "is a subuniverse" (closed under the basic operations);Sg 𝑨 G— the inductively generated subuniverse, withsgIsSub(it is a subuniverse) andsgIsSmallest(the generation theorem / universal property);⋂s— an arbitrary intersection of subuniverses is a subuniverse (the infinitary meet).
So assembling the lattice is a "step-3"-style task, closely parallel to the congruence-lattice assembly.
Tasks¶
- Define
Sub 𝑨(the type of subuniverses, as a Σ of a predicate with its subuniverse proof) and the inclusion order_≤_(=_⊆_). - Meet
B ∧ C = B ∩ C, joinB ∨ C = Sg(B ∪ C). -
Sub-Lattice : (𝑨 : Algebra α ρ)(ℓ₀ : Level) → Lattice _ _ _, at the absorbing levelL = 𝓞 ⊔ 𝓥 ⊔ α ⊔ ℓ₀(whereSgstays atL). - Bounds: bottom
Sg ∅(smallest subuniverse) and topU(the whole carrier);Sub-BoundedLattice. - Infinitary meet
⋂(via⋂s) and joinSg(⋃ …);Sub-CompleteLatticeinstantiating theCompleteLatticerecord. - A small worked example.
Acceptance criteria¶
-
Sub-Lattice 𝑨/Sub-CompleteLattice 𝑨type-check and satisfy the (complete-)lattice axioms. - Bounds proved as
⊥/⊤. - At least one small worked example.
Notes¶
- Placement, mirroring the congruence case (
Setoid.Algebras.Congruences.CompleteLattice): the instance goes inSetoid.Subalgebras.CompleteLattice, instantiating the general record inSetoid.Algebras.Lattices.CompleteLattice. - A richer worked example — the subgroup lattice of a concrete finite group — is appealing but a sizeable undertaking (defining the group over a signature, classifying its subgroups); it is tracked as a separate follow-up so this PR can stay focused.
Issue M6-12: Worked example: the subgroup lattice of a concrete finite group (#374, closed)¶
Labels: milestone-6-flrp
Description¶
Follow-up to the subalgebra-lattice infrastructure (#373). Once Sub 𝑨 is available as a complete lattice, a compelling worked example is the subgroup lattice of a concrete finite group — e.g. ℤ/4ℤ (the 3-element chain 0 < ⟨2⟩ < ℤ/4ℤ), the Klein four-group V₄ (the diamond M₃-minus, i.e. 2³-style with three order-2 subgroups), or S₃ (the well-known six-subgroup lattice).
This is separated from #373 because it is a sizeable undertaking on its own:
- realize the group concretely as a setoid algebra over a group signature (the
Classical/tree has group machinery to draw on); - identify the subuniverses (= subgroups, since the signature includes inverse and identity);
- classify them and exhibit the lattice order, ideally matching a known finite lattice.
Acceptance criteria¶
- A concrete finite group built as a
Setoidalgebra. - Its subgroups exhibited as elements of
Sub 𝑨, with the lattice order between them. - Prose identifying the resulting lattice (chain / diamond /
S₃lattice).
Notes¶
- Subuniverses of a group algebra are exactly its subgroups precisely because the signature carries the unary inverse and the nullary identity, so closure under the operations forces the subgroup axioms — worth stating explicitly in the example.
Issue M6-13b: FLRP WP-2: group-action infrastructure — subgroups, core, cosets, G-sets, Sub(G), intervals (#453, closed)¶
Labels: research-exploratory, flrp-research
Description¶
Reusable group-theoretic infrastructure needed by the Pálfy–Pudlák bridge (WP-3) and the enforceability framework (WP-4): subgroups as subalgebras with Sub(G) as a complete lattice (generalizing the Klein-four worked example Examples.Setoid.SubgroupLattice), conjugation/normality and the normal core Core_G(H), cosets with the transitive coset G-set as a unary algebra, and upper intervals [H, G] as bounded lattices. Per roadmap § 6 this lands in the Classical/ and Setoid/ trees, not in FLRP/, so the library gains value independently of the research program.
Part of ualib/agda-flrp#2.
Tasks¶
- Subgroups of a
Groupas subuniverses/subalgebras;Sub(G)viaSetoid.Subalgebras.CompleteLattice. - Conjugation, normal subgroups, and
Core_G(H)(largest normal subgroup ofGbelowH). - Cosets
G/Hand the coset G-set as a unary algebra (one operation per group element). - Upper intervals
[H, G]inSub(G)as bounded lattices. - Dedekind's rule
A ≤ B → A(C ∩ B) = AC ∩ Bat least stated (its proof may land here or in RP-1).
Acceptance criteria¶
- New modules type-check under the standard pragma; changes are additive.
- The Klein-four subgroup-lattice example still type-checks.
Scope note: this is the largest WP; splitting into WP-2a (subgroups/core) and WP-2b (cosets/G-sets/intervals) at PR time is acceptable and expected if the diff grows.
Issue M6-15: FLRP: formalize the unary-reduction theorem Con 𝑨 = Con ⟨A, Pol₁(𝑨)⟩ (#501)¶
Labels: milestone-6-flrp, research-exploratory, flrp-research
Description¶
Formalize the unary-reduction theorem for congruence lattices: the congruences of an algebra are exactly the equivalence relations compatible with its unary polynomial operations, so Con 𝑨 = Con ⟨A, Pol₁(𝑨)⟩ (McKenzie–McNulty–Taylor, Algebras, Lattices, Varieties I, Theorem 4.18). The manuscript docs/papers/fin-lat-rep/SmallLatticeReps.tex invokes this reduction at the start of its Kurzweil–Netter duality proof ("we can assume that F consists of unary operations"), and the closure method of its § Concrete Representations (the λ(L) operator, the filter–ideal lemma) lives entirely in the unary world, so this theorem is the bridge from the library's general signatures to those arguments.
Context: the WP-5 closure toolkit (#456) deliberately avoided this reduction — the product and ordinal-sum witness constructions carry general signatures directly — but the planned formal proof of Kurzweil–Netter duality (#502) needs it, and it is independently useful infrastructure for the FLRP program (#451).
Tasks¶
- Unary polynomial operations of a setoid algebra: terms in one variable with constants from the carrier, or the inductive closure of the basic operations under composition and point substitution; pick one canonical presentation and prove it closed under composition.
- The reduction theorem at Layer S: an equivalence relation is a congruence of
𝑨iff it is compatible with every unary polynomial; henceCon 𝑨andConof the unary reduct are equal as posets (mutual≑, order preserved). - The Layer-D corollary for finite finitary algebras: the unary reduct is again finite finitary (unary polynomials of a finite algebra are finitely many up to extensional equality, which is decidable on a finite carrier), and
DecContransports across the reduction. - Placement per roadmap § 6: the polynomial machinery is reusable mathematics and belongs in the
Setoid/tree (e.g. besideSetoid.Terms), not underFLRP/.
Acceptance criteria¶
- Type-checks under
--safewith no postulates; the reduction is stated and proved at Layer S with the Layer-D transport for finite finitary algebras.
Issue M6-18: Minimal normal subgroups exist in finite groups (well-founded descent) (#510, closed)¶
Labels: enhancement, milestone-6-flrp, flrp-research
Description¶
Prove that every nontrivial normal subgroup of a finite group contains a minimal one, by well-founded descent on order, and discharge the hypothesis it currently stands in for.
This single fact is the last finiteness gap in the parachute structure theory. It is assumed twice today, both times as an explicit argument and never as a postulate:
- RP-1 (#506) threads it as the
Mparameter ofGroupParachute.Structure.Minimal— the minimal normal subgroup whose centralizer Lemma 3.7 (i) computes (docs/notes/flrp-rp1-parachutes.md§ 4, fourth assumption); - RP-2 (#507) threads it as
MinimalNormalDescent, the antecedent of the enforced property in catalog Entries 1–3, so that the quantifier over normal subgroups in𝒢₃and𝒢₄is not silently narrowed (docs/notes/flrp-rp2-catalog.md§ 4.2).
Discharging it turns those entries into the note's statements verbatim.
Tasks¶
- Decide the finiteness interface:
FiniteAlgebraon the underlying algebra gives a decidable setoid equality and a surjective enumeration, from which a measure on equality-respecting subgroups (the number of enumerated elements satisfying a decidable membership predicate) is computable — note this needs the Layer-D presentation of the subgroup (decidable membership), exactly asIntervalᵈdoes; a semantic-only subgroup has no computable order. - Well-founded descent: a strictly decreasing chain of nontrivial normal subgroups terminates, using
Data.Nat.Induction's<-well-foundedness on the measure. - Conclude
MinimalNormalDescentfor a finite group with decidably presented normal subgroups, and instantiate RP-1'sMinimalmodule from it. - Update the two design notes and drop the antecedent from catalog Entries 1–3.
Acceptance criteria¶
- Type-checks under
--safe, no postulates; the Layer-D requirement (if any) is stated explicitly per ADR-008 rather than smuggled in. -
FLRP.ReductionsEntries 1–3 readcfIE 𝒢ᵢ ⊕ᵖ-Latticewith no conditional antecedent, for finite groups.
Follow-up to ualib/agda-flrp#8 / ualib/agda-flrp#9. Part of ualib/agda-flrp#2.
Issue M6-20: Solvability and the alternating/symmetric predicates (#512)¶
Labels: enhancement, milestone-6-flrp, flrp-research
Description¶
Define solvability and being an alternating or symmetric group in the library, turning four RP-2 catalog entries from schemas into statements.
FLRP.Reductions (#507) parameterizes Entries 4, 5, 7, and 8 by an abstract group predicate together with the facts their sources supply about it, because neither notion is definable in the library today (docs/notes/flrp-rp2-catalog.md § 4.8). The schemas instantiate unchanged once the predicates exist, and the exercise made explicit which properties are actually used: for solvability, only H-closure and the Mₙ exclusion.
Solvability additionally closes an RP-1 open item: the second half of the note's Lemma 3.7 (ii), "a group with a nonabelian minimal normal subgroup is nonsolvable" — the sharper structural fact (Minimal.nonabelian) is already proved (#506).
Tasks¶
- Solvability: the derived series (commutator subgroups iterated) or a subnormal abelian series; prove the class closed under homomorphic images (this is exactly
Entry-𝒢₀.SolvableHClosed), and that a group with a nonabelian minimal normal subgroup is nonsolvable. -
AₙandSₙ: the symmetric group onFin nexists in embryo (Examples.Classical.Groups.SymmetricGroup3); generalize toSym (Fin n)and the alternating subgroup, and defineAltOrSym 𝒢as "isomorphic toAₙorSₙfor somen". Prove H-closure (Entry-𝒢₁.AltSymHClosed): the quotients ofAₙ/Sₙare again alternating or symmetric. - Instantiate the four catalog schemas at the new predicates and simplify the survey note § 4.8.
- Close the degree-
≤ 4gap of Entry 5 (survey note § 3): Basile's Theorem D assumes degree at least 5, and the small cases were checked by hand, not machine-checked. Note that the check is not vacuous —[V₄ , S₄] ≅ M₄, soM₄does occur in a symmetric group and onlyM₆(and higher counts outside{1,2,3,5,7,11}) is safe. Either decide the small cases by computation overFin-presentedAₘ/Sₘform ≤ 4, or restrict the imported hypothesis to degree≥ 5and compose Entry 5 with Entry 4 through "every alternating or symmetric group of degree≤ 4is solvable".
Acceptance criteria¶
- Both predicates are defined in
Classical/(reusable mathematics, roadmap § 6), not underFLRP/. - The two H-closure hypotheses of
FLRP.Reductionsare proved rather than assumed, and the entries no longer take an abstract predicate.
Follow-up to ualib/agda-flrp#9 / ualib/agda-algebras#507; also closes an open item of ualib/agda-flrp#8. Part of ualib/agda-flrp#2.
Issue M6-22: Normal subgroups and congruences of a group: the missing correspondence (#508, closed)¶
Labels: enhancement, milestone-6-flrp, flrp-research
Description¶
Formalize the correspondence between normal subgroups of a group and congruences of it, and use it to identify the group-side monolith notion with the library's congruence-side one.
Classical.Structures.Group.MinimalNormal (added by ualib/agda-algebras#507) defines HasMonolithᵍ — a least nontrivial normal subgroup — because the library has no way to say "this group is subdirectly irreducible" in the sense of Setoid.Congruences.Monolith.IsSubdirectlyIrreducible, which is a statement about Con 𝑨. The RP-2 catalog's Entry 1 (𝒢₂) is therefore stated group-side, with the divergence recorded in docs/notes/flrp-rp2-catalog.md § 4.1. This issue retires that divergence.
The work is ordinary — no obstruction and no classical input — and it is reusable mathematics, so per roadmap § 6 it belongs in Classical/Structures/Group/, beside FLRP.Bridge's Pálfy–Pudlák correspondence, not under FLRP/.
Tasks¶
- From a normal subgroup
N, the relationx θ y ⟺ x y⁻¹ ∈ Nis a congruence of the group algebra: reflexivity, symmetry, transitivity,≈-respect, and compatibility with the three operations ofSig-Group. - From a congruence
θ, the class{x : x θ ε}is an equality-respecting normal subgroup. - The two maps are monotone and mutually inverse (up to
≑on congruences and mutual inclusion on subgroups), hence an order isomorphismCon 𝑮 ≅ Normal(𝑮); nontriviality of the subgroup corresponds toNonzeroof the congruence. - Transport
HasMonolithᵍtoHasMonolith, givingIsSubdirectlyIrreducibleᵍ 𝒢 → IsSubdirectlyIrreducible (proj₁ 𝒢); the least-element form needed formono-leastis already available asminimal-meets→least. - Retire the
ᵍsuperscript inMinimalNormal(FLRP modules are exempt from the deprecation cycle, roadmap § 1, so the rename can be direct) and update the𝒢₂entry ofFLRP.Reductionsplus § 4.1 of the survey note.
Acceptance criteria¶
- Type-checks under
--cubical-compatible --exact-split --safewith no postulates. -
𝒢₂ofFLRP.Reductionsis stated with the library'sIsSubdirectlyIrreducible, and the survey note's § 4.1 divergence is replaced by a pointer to the bridge.
Follow-up to ualib/agda-flrp#9 / ualib/agda-algebras#507. Part of ualib/agda-flrp#2.
Issue M6-23: Powers, diagonals, and the interval [D , Sⁿ] (#521, closed)¶
Labels: enhancement, milestone-6-flrp, flrp-research
Description¶
Build the group infrastructure that Kurzweil's construction needs — the power Sⁿ of a group, its diagonal subgroup D, and the interval [D , Sⁿ] — once, in Classical/, so that both FLRP consumers import the same definitions: RP-4's wreath no-go (#461, Lemma 3.3 of the vendored note docs/papers/flrp/ieprops/) and the Kurzweil–Netter duality proof (#502, WP-5 stretch). Reusable mathematics lands in the Classical/ tree per roadmap § 6; the FLRP-facing interval packaging composes with FLRP.Enforceable's UpperInterval / IntervalIso, the interval presentation everything downstream expects.
The mathematical target is Kurzweil's lemma (lem:latt-duals of docs/papers/fin-lat-rep/SmallLatticeReps.tex, discussed in DeMeo's thesis § 2.2): for S a finite nonabelian simple group, the interval [D , Sⁿ] in Sub(Sⁿ) is isomorphic to Eq(n)′, the dual of the partition lattice of an n-element set. Both written sources prove only the order-reversing embedding π ↦ K_π = { y ∣ ker π ≤ ker y }; the surjectivity half — every subgroup between D and Sⁿ is such a K_π, the step where nonabelian simplicity enters — is cited to Kurzweil's 1985 article and not reproved. The formal treatment mirrors that split honestly:
- everything the sources actually prove is formalized unconditionally — the power, the diagonal, the partition subgroups with their membership characterizations, the partition lattice
Eq(n)itself as a level-0 equationalLattice(on the Freese normal-form parent vectors ofSetoid.Congruences.Certificates.Schema, which are exactly the idempotent decreasing mapsIC(n)the sources use), and the dual order-embeddingEq(n) → [D , Sⁿ]; - surjectivity is registered as
FLRP.AssumptionsEntry 4 in the established per-entry style (statement, source and citation, status, layer, retirement path), stated so that it hands the consumer the partition witness; the assembledIntervalIso [D , Sⁿ] ≅ Eq(n)′is then a proved theorem conditional on the entry, and retiring the entry (a follow-up issue: the normal-subgroup structure of powers of a nonabelian simple group, plus the induction over blocks) upgrades it with no change to consumers.
Tasks¶
- The indexed product
⨅ᵍof groups and the power_^ᵍ_(carrierFin n → S, pointwise operations), generalizing the binary_×ᵍ_ofClassical.Structures.Group.Productrather than duplicating it; satisfaction transfers by⊧-P-invarofSetoid.Varieties.Properties. Coordinate projections and pointwise descriptions of the curried operations. - The diagonal
D = { (s , … , s) }as an equality-respecting subgroup ofSⁿ, with its membership characterization. - The partition lattice
Eq(n)as aClassical.Small.Structures.Lattice, order-first on normal-form parent vectors: kernel-inclusion order, computable meet and join, lattice laws derived from the order, and thedualLatticeinstance. - Partition subgroups
K_πwithD ≤ K_π ≤ Sⁿ, the membership characterizationy ∈ K_π ⟺ ker π ⊆ ker y, and the dual order-embedding (order-reversal in both directions; the reflection direction consumes nontriviality ofS). - The interval
[D , Sⁿ]as anUpperIntervalinstance, and the conditional theorem assemblingIntervalIso (Sⁿ) D (dualLattice (Eq n))from Entry 4. -
FLRP.AssumptionsEntry 4: Kurzweil interval surjectivity, per-entry documentation and retirement path. - Consumer interface sanity check: state (as type definitions, not proofs) the signatures RP-4 (#461) and Kurzweil–Netter (#502) will call, and confirm they typecheck against what was built.
Acceptance criteria¶
- Type-checks under
--cubical-compatible --exact-split --safewith no postulates; classical inputs enter only through the named Entry 4 hypothesis. -
make check,make unused-imports, andmake check-links(aftermake gen-links) are green.
Consumers: ualib/agda-flrp#11, ualib/agda-flrp#20. Part of ualib/agda-flrp#2; roadmap §§ 2, 6.
Milestone 6 Dependencies¶
M6-1 (Con(A) as a lattice) is the foundation: both subdirect products and Maltsev conditions need congruences-as-a-lattice to be phrasable in the form the classical proofs use.
graph TD
M3_5["M3-5: Lattice"]:::ext
M6_1["M6-1: Con(A) lattice"]
M6_2["M6-2: Subdirect products"]
M6_3["M6-3: Maltsev conditions"]
M3_5 --> M6_1
M6_1 --> M6_2
M6_1 --> M6_3
classDef ext fill:#f0f0f0,stroke:#999,stroke-dasharray: 4 3,color:#555
---¶
Milestone 7 — Algebraic complexity / CSP extensions (finite templates)¶
Issue M7-1: Extend Complexity module beyond Basic and CSP (#274)¶
Labels: milestone-7-csp, design-discussion
Description¶
The current Base.Complexity module has only two submodules (Basic and CSP). The CSP module is little more than a bare definition with no theorems. This is a separate research track from the FLRP (M6): the FLRP is about which lattices arise as congruence lattices of finite algebras, while finite-template algebraic CSP is about the complexity of constraint satisfaction problems as a function of the polymorphism clone of the underlying finite relational structure. Both use universal algebra, but they are different questions. Infinite-template extensions (ω-categorical, Bodirsky–Pinsker) are covered separately under M9-2.
This issue is research-flavored and best decomposed after discussion.
Tasks¶
Candidate content, to be prioritized:
- Polymorphism clones:
Pol(A, Γ)as a first-class type. - The Jeavons Galois connection between invariant relations and polymorphism clones.
- Post's lattice (for Boolean clones).
- Specific CSP tractability classes as worked examples (Horn-SAT, 2-SAT, linear systems over finite fields).
- Statement (not necessarily proof) of the Bulatov–Zhuk algebraic dichotomy.
Acceptance criteria¶
- Polymorphism clones available as a type with basic operations.
- Jeavons Galois connection is proved for a fixed finite domain, OR a clear research-plan issue is filed continuing the work.
Milestone 7 Dependencies¶
M7-1 (#274) depends on M2-7c (#307) for the canonical-path Complexity content. Sequencing: #307 ports the existing module; this issue extends it.
---¶
Milestone 8 — LLM readiness and corpus artifacts¶
Issue M8-1: Publish (theorem, proof) corpus for LLM training (#275)¶
Labels: documentation, milestone-8-llm
Description¶
Once Setoid/ and Classical/ are stable post-M4, publish a training and retrieval corpus for language models.
Tasks¶
- Design a schema for corpus records: module path, theorem statement, proof term, dependencies, prose summary, keywords.
- Implement an extractor that walks the library and emits records.
- Publish as a Hugging Face dataset.
- Add a CI job that regenerates the corpus on each release.
- Write a short paper or blog post describing the dataset.
Acceptance criteria¶
- Dataset published with ≥ 500 (theorem, proof) records.
- CI regenerates on release.
- Write-up is public.
Issue M8-2: Explore integration with agda-native-air (#276)¶
Labels: milestone-8-llm, design-discussion
Description¶
agda-native-air (a parallel project on AI-assisted formal proof) is a natural consumer of the agda-algebras corpus. This issue tracks the integration. Exploratory; low-priority until agda-native-air stabilizes.
Tasks¶
- Document what API / metadata / annotations agda-native-air needs from agda-algebras.
- Identify any agda-algebras design choices that help or hinder agda-native-air consumption.
- Write an integration report.
Acceptance criteria¶
- Integration report exists in
docs/integration-agda-native-air.md. - Any design changes required are filed as separate issues.
---¶
Milestone 9 — Applications of continuous relations¶
Issue M9-1: Scott-continuous relations on DCPOs using Relations.Continuous (#282)¶
Labels: design-discussion, milestone-9-apps
Description¶
The Base.Relations.Continuous formalization generalizes classical relations: the arity is an arbitrary type rather than a natural number, and compatibility with an operation is stated pointwise over that arity. That shape turns out to be the right one for a notion with a distinguished mathematical pedigree: Scott-continuous relations on directed-complete partial orders (DCPOs).
A relation R ⊆ X × Y between DCPOs is Scott-continuous when, for every directed family {(xᵢ, yᵢ)}ᵢ∈I in R, the supremum (⊔ xᵢ, ⊔ yᵢ) is again in R. This is a statement about arbitrary-arity suprema — the index set I is genuinely arbitrary — and factors through the continuous-relation API naturally.
The broader context is domain theory in the Scott sense, which underlies the denotational semantics of typed lambda calculi, topologically-enriched model theory and partial-function spaces, and constructive analysis via Escardó's work on exhaustively searchable sets. The Escardó connection is worth flagging: his LICS 2007 result "Infinite sets that admit fast exhaustive search" characterizes searchable sets via a topological continuity condition on their decision procedures, and provides a computability-flavored reason to care about Scott-continuous relations on specific DCPOs such as the Cantor space.
Tasks¶
-
Classical/Order/DCPO.agda(orSetoid/Order/DCPO.agdaif it will be adapted for Cubical later): DCPO as a record bundle — a poset with directed suprema. -
Classical/Order/ScottContinuous.agda: aScottContinuouspredicate on pairs of aContinuousrelation and a DCPO structure on its carriers. - Basic closure properties: Scott-continuous relations are closed under composition, intersection, and directed unions of Scott-continuous families.
- At least one non-trivial example: the graph of a Scott-continuous function is Scott-continuous as a relation; conversely, a single-valued Scott-continuous relation is the graph of a Scott-continuous function.
- Optional stretch goal: a path to Escardó's characterization of searchable sets, formalized as far as tractable. If
TypeTopologyis the cleanest source, import from there rather than re-derive.
Acceptance criteria¶
- DCPO record and ScottContinuous predicate type-check.
- The graph-of-continuous-function ↔ single-valued-continuous-relation characterization is proved.
- At least one closure property (composition or directed union) is proved.
- A short public write-up (blog post or arXiv note) connects the formalization to domain theory.
Why this belongs in agda-algebras¶
Universal algebra and order theory have a long shared history: every algebra with a compatible order gives an ordered algebra; Birkhoff's theorem has order-enriched variants; congruence lattices (the central FLRP object) are themselves DCPOs. Housing the Scott-continuous-relation material in agda-algebras keeps related abstractions together and gives them a shared foundation in the continuous-relation API.
Relation to other milestones¶
- Depends on: M2 (Setoid/ canonical), M3-1 (Classical/ scaffold).
- Independent of: M6 (FLRP), M7 (finite-template CSP).
- Informs: M5 (Cubical port) — Scott-continuous relations have a natural cubical-friendly statement using paths.
Issue M9-2: Infinitary CSP over ω-categorical templates via continuous relations (#281)¶
Labels: design-discussion, milestone-9-apps
Description¶
The CSP module under M7 targets finite-template CSPs with finite-arity relations. A rich body of contemporary work — most visibly the Bodirsky–Pinsker program — studies CSPs whose template is an ω-categorical structure with a countable domain and potentially infinitary relations. The central tools there include:
- Polymorphism clones of ω-categorical structures, which control CSP complexity via a topological-dynamical analog of the finite-domain algebraic approach.
- Canonical functions in a polymorphism clone: functions whose behavior on all "types" is determined by their behavior on finitely many representatives. See Michael Pinsker's recent work (e.g. arXiv:2502.06621).
- Birkhoff-style theorems for topological clones, generalizing the classical HSP theorem from varieties to polymorphism clones with a topological structure.
The Base.Relations.Continuous formalization in agda-algebras happens to be exactly the right abstraction for this setting. An ω-categorical template has relations whose natural arity is a countable index set; a continuous-in-our-sense relation drops in unchanged.
This is a design-discussion issue, not an implementation plan.
Tasks¶
- Which definitions port over unchanged from
Setoid/Complexity/CSP(post M7-1), and which need generalization? - What is the minimal API for a "template" in the ω-categorical setting (base structure, automorphism group, topological structure)?
- Is there a natural "Birkhoff for topological clones" result whose formalization is tractable with current tooling? Bodirsky, Pinsker, and collaborators have published multiple variants; select the one with the cleanest statement.
- Can a small but genuinely infinitary example be formalized end-to-end — e.g. the template
(ℚ, <)for temporal constraint satisfaction, which is ω-categorical and has a well-understood polymorphism clone?
Deliverables (if pursued)¶
- A new subtree
Classical/Complexity/Infinitary/(or similar) with the generalized definitions. - A single formalized example (suggestion: the template
(ℚ, <)). - A short write-up — blog post or arXiv note — connecting the formalization to the Bodirsky–Pinsker literature.
Non-goals¶
- Formalizing the full Bodirsky–Pinsker dichotomy conjecture.
- Matching the generality of any existing implementation.
- Engaging with decidability or tractability results (those are downstream; the first task is having the definitions).
Relation to other milestones¶
- Depends on: M2 (Setoid/ canonical), M3-1 (Classical/ scaffold).
- Benefits from: M7-1 (finite-template CSP infrastructure — polymorphism clones, Galois connection machinery).
- Independent of: M5 (Cubical), M6 (FLRP).
Issue M9-3: Exploratory: coalgebraic bisimulation as a continuous relation (#283)¶
Labels: design-discussion, milestone-9-apps
Description¶
An exploratory issue, not a deliverable. The goal is to read, think, and write up findings about whether the Continuous relation API has novel applications in coalgebra, particularly for bisimulation of non-finitary coalgebras.
A bisimulation between F-coalgebras (c : A → F A, d : B → F B) is classically a relation R ⊆ A × B that lifts along F: if (a, b) ∈ R then there is a witness (F R) (c a) (d b). When F is a finitary polynomial functor (e.g. finite-branching trees), R is naturally a finite-arity relation. When F is continuous — for example, the stream functor F X = X × A, or the unbounded-branching tree functor F X = X ^ ℕ — the natural witness type for a bisimilarity step is an arbitrary-arity relation. This is where the Continuous API might fit.
The intersection of coalgebra and classical universal algebra has many smart people (Rutten, Jacobs, Kurz, Adámek, Pattinson, et al.), but most of that work targets theoretical-CS applications (automata, regular languages, process calculi). It is much less developed on the universal-algebra-in-the-Birkhoff-sense side. It is plausible that low-hanging fruit remains at the intersection, but finding it requires sustained reading, not speculation.
Progress on this issue is measured in paragraphs written, not in type-checked Agda.
Tasks¶
- Read Rutten, "Universal coalgebra: a theory of systems," TCS 2000 (the standard introduction).
- Read one or two recent survey articles on coalgebraic bisimulation for continuous functors.
- Write up (in
docs/exploration/coalgebra.md) what the natural coalgebra-with-continuous-arity examples look like, and whether theContinuousAPI fits them without modification. - Identify at least one concrete formalization candidate, even if small (e.g. a bisimulation characterization of stream equality using the
ContinuousAPI). If no such candidate emerges, document why. - Optional: formalize the candidate, or file a follow-up M9-3a issue.
Acceptance criteria¶
-
docs/exploration/coalgebra.mdexists and is at least 2000 words. - The document contains a concrete verdict: either "there is a formalization project worth pursuing" (in which case a follow-up issue is filed) or "the area is saturated / the fit is not natural" (in which case this issue is closed).
Non-goals¶
- Producing a polished, publishable result. This is scoping work.
- Committing to a specific subarea of coalgebra. The reading should be broad enough to spot the low-hanging fruit, whatever it turns out to be.
Relation to other milestones¶
- Completely independent of every other milestone. This is a long-tail exploratory investigation.
Milestone 9 Dependencies¶
M9-1 and M9-2 depend on M2 (Setoid/ canonical) and M3-1 (Classical/ scaffold). M9-2 additionally benefits from M7-1's CSP infrastructure but does not strictly require it — the infinitary definitions can be developed in parallel and harmonized later. M9-3 is independent of every other milestone.
graph TD
M2_1["M2-1: Freeze Base"]:::ext
M2_7c["M2-7c: Port Complexity"]:::ext
M2_7d["M2-7d: Port Continuous"]:::ext
M3_1["M3-1: Classical/ scaffold"]:::ext
M3_5["M3-5: Lattice"]:::ext
M7_1["M7-1: Finite CSP"]:::ext
M9_1["M9-1: Scott-continuous relations"]
M9_2["M9-2: Infinitary CSP"]
M9_3["M9-3: Coalgebra exploration"]
M2_1 --> M9_1
M2_1 --> M9_2
M2_7d --> M9_1
M2_7d --> M9_2
M2_7d -.-> M9_3
M2_7c --> M9_2
M3_1 --> M9_1
M3_5 --> M9_1
M3_1 --> M9_2
M7_1 -.-> M9_2
classDef ext fill:#f0f0f0,stroke:#999,stroke-dasharray: 4 3,color:#555
M2-7d → M9-1, M9-2added as solid edges;M2-7d -.-> M9-3added as dashed (M9-3 only consumes if it produces a formalization candidate, per its own body).M2-7c → M9-2added as solid (per the audit; M9-1 explicitly does not depend on Complexity).M3-5 → M9-1added — this is technically a pre-existing dependency that the original graph missed. M9-1's body explicitly invokes "DCPO as a record bundle — a poset with directed suprema," which depends on lattice/order infrastructure that M3-5 produces. Worth flagging since the audit surfaced it.
---¶
Milestone 10 — Post-3.0 polish¶
Issue M10-1: doc rendering-pipeline modernization (mkdocs) (#295, closed)¶
Labels: documentation, breaking-change, milestone-10-polish
Context¶
M1-8 / PR #294 proposes consolidating the current dual-tree literate-Agda layout into single-file .lagda.md modules under src/. This issue tracks the rendering-pipeline modernization that should follow once that migration lands.
The shared root cause is the same: if the source tree is migrated to Markdown-literate .lagda.md files, the current Jekyll-based admin/generate-html + admin/generate-tex pipeline will no longer be the natural fit. In that post-migration layout, agda --html --html-highlight=code on a .lagda.md file already produces Markdown with fenced code blocks and (when paired with kramdown attribute spans, per ADR-004 and agda-lagda-migrator#14) inline-highlighted Agda terms. A modern static-site generator that reads Markdown directly would then be the right shape for the rendering pipeline; the Agda community's de facto choice for that role is MkDocs with the Material theme.
Open design questions¶
A short discussion is needed before code is written. The resolutions should be recorded in docs/adr/005-mkdocs-rendering-pipeline.md.
- Domain. Recommendation: keep https://ualib.org. It is the existing public URL of the rendered library; preserving it avoids breaking every external link to a
Module.Submodule.htmlpage. Alternatives are out of scope here (see "Non-goals" below). - agda-html integration. Two viable architectures — (a) preprocess
.lagda.mdfiles by runningagda --html --html-highlight=codeand pointing MkDocs at the generated Markdown, vs. (b) point MkDocs directly at.lagda.mdand rely on kramdown attribute spans + a custom CSS for highlighting (noagda --htmlstep in the rendering pipeline). Recommendation: (b), because it eliminates a build-time dependency and matches what 1Lab andagda-lagda-migratoralready produce. The trade-off is that whole-token-by-token Agda highlighting (the kindagda --htmlproduces) is sacrificed in favor of class-tagged inline references; in practice the latter is what readers actually use. - MkDocs plugins. Baseline:
material,search(built-in),mkdocs-macros-plugin(for the equivalent of Jekyll's{% include %}directive),mkdocs-redirects(to absorb the small set of post-3.0 URL changes). Open: whether to add a Mermaid plugin for the dependency graphs indocs/GITHUB_PROJECT.mdonce they're rendered there too. - Custom CSS. Recommendation: adapt the formal-ledger-specifications
custom.css(referenced fromagda-lagda-migrator#14's PR description) for kramdown-attribute-span styling. Light and dark themes; per-Agda-class colors (AgdaFunction,AgdaBound,AgdaRecord,AgdaSymbol,AgdaArgument).
Proposal¶
Pre-work¶
- Write
docs/adr/005-mkdocs-rendering-pipeline.mdresolving the open questions above. - Confirm that the existing
_includes/UALib.Links.mdcontent is reproducible under MkDocs' macros plugin (or under a simple Markdown reference-link include scheme).
Tooling¶
- Add
mkdocs.ymlat the repo root withtheme: material, navigation tabs configured to mirror the existingdocs/GITHUB_PROJECT.mdordering, and theagda-algebraslibrary section linking to thesrc/tree. - Add
docs/stylesheets/custom.csswith kramdown-attribute-span styling for the five Agda classes. - Add
docs/javascripts/only if a specific JS dependency is required (e.g., a search hook); avoid by default. - Add a top-level
make sitetarget that runsmkdocs build, withmake servefor local preview (mkdocs serve). - Add a Nix shell input for MkDocs + Material so the rendering pipeline is reproducible under
nix develop.
Content migration¶
- Move the shared link definitions to a dedicated
docs/_links.mdreferenced from each module (or provide the equivalent undermkdocs-macros-plugin). - Rewrite
docs/_links.md's entries: strip thedocs/lagda/paths, point each entry at the newsrc/X/Y/Z.lagda.mdpath. - Rebrand legacy prose for the post-M2-1 module names. Across
src/Legacy/Base/**/*.lagda.md: front-mattertitle:fields still say "Base.X.Y module"; reference-style links of the form[Base.X.Y][]in prose comments don't resolve; bottom-of-page nav links targetBase.htmlfiles that no longer exist after the rename toLegacy.Base/. This was deliberately deferred from PR #300 (the freeze rewrote onlymodule,import,open importlines — the syntactic positions Agda's type checker reads — leaving prose untouched). Rebranding piecemeal would create inconsistency; doing it as part of the rendering-pipeline migration is the natural moment because the Markdown reference targets and nav scheme are themselves changing here. - Audit the
src/**/*.lagda.mdcorpus for any surviving\href{...}{...}LaTeX-link macros (theagda-lagda-migrator#14rewrite catches these but a sweep is cheap insurance) and any surviving raw@@AgdaTerm@@...@@placeholders.
CI / deploy¶
- Add a GitHub Actions workflow
.github/workflows/docs.ymlthat builds the MkDocs site on every push tomasterand deploys togh-pages(usingmkdocs gh-deploy --forceorpeaceiris/actions-gh-pages). - Configure GitHub Pages to serve from
gh-pageswith custom domainualib.org. - Configure DNS at the registrar to point
ualib.org(andwww.ualib.org) at GitHub Pages' IPs. - Spot-check at least 10 rendered pages against the pre-migration archive at the current
https://ualib.org.
Tooling cleanup¶
- Delete
admin/generate-html,admin/generate-tex,admin/illiterator/. - Delete
_layouts/,_config.yml, and any other Jekyll-only files at the repo root or underdocs/. - Remove the
make htmltarget and replace it withmake site; updateMakefile,README.md, andINSTALL.mdaccordingly.
Acceptance criteria¶
-
make sitebuilds the full library atsite/(or wherever MkDocs writes output) without errors. - Spot-checked rendered pages match the pre-migration archive in content; minor styling differences are acceptable.
-
https://ualib.orgserves the new MkDocs site; existingModule.Submodule.htmlURLs continue to resolve (withmkdocs-redirectscovering any path that legitimately moved). -
admin/generate-html/,admin/generate-tex/, andadmin/illiterator/no longer exist in the tree. -
docs/adr/005-mkdocs-rendering-pipeline.mdis merged. -
CHANGELOG.mdrecords the rendering-pipeline change under[Unreleased] / Changed.
Non-goals¶
- Moving the documentation to a different domain.
formalverification.organdagda-algebras.orgare tracked as separate considerations if at all; this issue does the obvious-and-stable thing and keepsualib.org. - Re-litigating the choice of MkDocs over alternatives (Hugo, Zola, Quarto, etc.). MkDocs is the de facto standard in the Agda ecosystem and the choice tracks ecosystem convention.
- Restructuring the module hierarchy or renaming any
.lagda.mdfile.
Related¶
- PR #294 — M1-8: migrate to Markdown-literate Agda.
- ADR-004 — Markdown-literate Agda as the canonical literate format.
agda-lagda-migrator#14— kramdown attribute spans (the convention this pipeline relies on).- Issue #280 — original M1-8 issue (closed by #294).
Why now¶
The rendering pipeline is the last piece of the M1-8 story. Deferring it indefinitely leaves admin/generate-html and the Jekyll machinery as dead code in the tree, ages the deferred-CHANGELOG entries, and blocks the make corpus target from M8 (LLM readiness) which wants the same .lagda.md walker MkDocs will exercise. The work is bounded: MkDocs configuration is small, the kramdown-attribute-span scheme is already proven against the agda-algebras corpus by agda-lagda-migrator#14, and the deploy step is a known-good Actions-to-Pages flow.
Issue M10-2: offer to transfer agda-algebras to the agda organization (#298)¶
Labels: milestone-10-polish, governance, agda-community
Motivation¶
Agda's umbrella organization, github.com/agda, already hosts the language itself, the standard library, the categorical-foundations library agda-categories, and other community-maintained core libraries. agda-algebras' current home at github.com/ualib reflects an earlier era; folding it into the umbrella agda org would
- signal community-curated rather than personal-project status,
- make discovery easier for users browsing Agda's GitHub presence,
- align the library's governance with the same patterns the rest of the ecosystem uses.
Pre-conditions¶
The transfer should happen after the library is in good shape. Concretely:
- 3.0 has shipped (M1–M5 complete, classical structures landed, CI green, documentation site live).
- CONTRIBUTING.md, CODE_OF_CONDUCT.md, governance model are stable.
- Maintainership beyond a single primary author is realistic — at least one additional reviewer with commit rights to the core tree.
The case for transfer rests on the library being something an org-level audience can rely on; transferring during a half-finished reconstruction would be premature.
Process¶
GitHub's "Transfer ownership" feature (Settings → General → Danger zone → Transfer) preserves stars, forks, watchers, issues, PRs, releases, and — critically — installs HTTP redirects from the old ualib/agda-algebras URLs to the new agda/agda-algebras URLs at the GitHub level. External links don't need to be rewritten on day one.
Tasks¶
- Approach the agda-org maintainers (Andreas Abel, Nils Anders Danielsson, etc.) informally first. Confirm they're amenable to hosting the library and what their org-level expectations are (CI, code of conduct, license, responsiveness on issues).
- File a tracking issue in
agda/agda-algebras(or wherever the discussion lives) for cross-referencing. - Execute the GitHub transfer.
- Update
README.md,INSTALL.md,CONTRIBUTING.md,CHANGELOG.md, the MkDocs site'smkdocs.yml, and any CI badge URLs to point atagda/agda-algebrasdirectly (the redirects work, but explicit URLs are more durable). - Update the
agda-algebras.cabal-style metadata (or whatever the equivalent is for an Agda library) to reflect the new home. - Announce on the Agda Zulip and the agda-algebras CHANGELOG.
Non-goals¶
- Renaming the repository.
agda-algebrasstaysagda-algebras. - Changing the library's API or any source content as part of the move.
- Migrating off the existing
ualib.orgdocumentation domain. That decision is independent and tracked separately.
Issue M10-3: Type-on-hover tooltips for Agda tokens (1Lab-style), with a toggle (#429, closed)¶
Labels: documentation, milestone-10-polish
Context¶
M10-1 (#295, PR #427) brought full agda --html token highlighting with per-token hyperlinks to definitions into the MkDocs site, plus the classic clickable-HTML site at /classic/. Tokens are now classed and linked; the natural next step — deferred from the #295 review — is type-on-hover tooltips (like 1lab.dev, and the less polished Ledger formal spec and Leios formal spec): hover a token, see a small popover with its definition, without leaving the page.
Goal¶
- Hovering any highlighted Agda token shows a popover containing its type signature (and, where available, its definition snippet / docstring).
- A "Tooltips on/off" toggle in the page header, persisted across pages (e.g.
localStorage), so readers who find them distracting can switch them off. - Light + dark styling consistent with the site theme.
Approach (proposed)¶
This builds directly on the make agda-md output already produced for #3a — no new Agda dependency:
- The
agda --html --html-highlight=codeoutput already contains every definition's type signature as highlighted code, anchored by char-offset id (the same ids the hyperlinks target). A small build step (agen-filespass or a hook) extracts{anchor → type-signature HTML}into a JSON index emitted into the site. - A small script under
docs/javascripts/attaches a popover on hover over any linked token, looking up the target anchor in the index (cross-page lookups resolve because the index is global). - A header button toggles a
localStorageflag that shows/hides the popovers (a Material header/announceoverride or a tiny custom element).
Scope¶
- MVP (this issue). Signature-on-hover from the existing
agda --htmloutput + the toggle. No new tooling beyond a JSON-index build step and a small JS/CSS bundle. - Stretch (separate issue if pursued). Fully normalised types / docstrings as 1Lab renders them — this needs the Agda API (a Shake/Haskell-style extractor), a materially larger effort.
Non-goals¶
- Re-deriving the highlighting or hyperlinks (done in #295 / PR #427).
- Agda-API type extraction (the stretch goal above).
References¶
-
295 — M10-1 rendering-pipeline modernization; PR #427 — its implementation.¶
- ADR-007 — the rendering pipeline this extends.
- 1lab.dev — the reference implementation of type-on-hover.
Issue M10-3: Distribute agda-algebras through nixpkgs as an Agda library (#299)¶
Labels: nix, milestone-10-polish, agda-community
Motivation¶
The repo's flake.nix provides a development environment — nix develop gives a contributor a pinned Agda + stdlib shell. It does not provide a consumer Nix package: a downstream Nix user who wants to depend on agda-algebras as a library has to vendor a flake input or rebuild the package themselves. Promoting agda-algebras to a first-class entry under nixpkgs.agdaPackages solves this and tracks how the rest of the Agda ecosystem is distributed (agdaPackages.standard-library, agdaPackages.agda-categories, agdaPackages.cubical, etc.).
Tasks¶
- Audit
nixpkgs/pkgs/build-support/agdaand the existingagdaPackages.*entries to confirm the packaging contract (build inputs,everythingFile, library-name conventions, version pinning). - Add a
pkgs/agda-modules/agda-algebras.nix(or whatever the current nixpkgs path is) defining the package: source from a tagged release onmaster, depend onstandard-library≥ 2.3, buildEverything.agda. - Open a PR against
nixpkgsadding the entry; coordinate with the nixpkgs Agda maintainers (look at recentagdaPackagesPRs for the right reviewer set). - Once accepted, update agda-algebras' own
flake.nixto expose the same library derivation as a flake output (so flake-based downstream users don't have to wait for the nixpkgs channel cycle). - Document the consumer-side usage pattern in
INSTALL.md:agdaPackages.agda-algebrasfor nixpkgs users;inputs.agda-algebras.lib.Xfor flake users. - Coordinate with each subsequent agda-algebras release: tag, update the nixpkgs entry's source hash, bump the package version.
Acceptance criteria¶
-
nix-shell -p 'agdaPackages.agda-algebras'produces a working environment in whichagda --library agda-algebrasresolves correctly. - The flake also exposes the library derivation:
nix build github:ualib/agda-algebras#lib(or the post-transferagda/agda-algebrasURL). -
INSTALL.mddocuments the nixpkgs consumer path alongside the existing development-environment path.
Non-goals¶
- Replacing the existing development flake. The development flake (
nix develop) is a different artifact and stays in place. - Distributing through any package manager other than nix. Agda libraries don't have a strong tradition of cross-package-manager distribution; the agda-stdlib is the closest thing to a canonical distribution channel and it's nixpkgs-anchored.
Issue M10-4: Retire and park the legacy ualib.org site; cut over to the MkDocs site (#430, closed)¶
Labels: documentation, milestone-10-polish
Context¶
PR #427 (closing #295) builds the new MkDocs (Material) site from the .lagda.md sources and deploys it to the gh-pages branch on every push to master.
By deliberate decision in ADR-007 (docs/adr/007-mkdocs-rendering-pipeline.md), the cutover — pointing GitHub Pages at gh-pages, attaching the ~~ualib.org~~ agda-algebras.universalalgebra.org custom domain, and the registrar DNS change — was left as a manual maintainer step so that merging the PR does not disturb the currently-live site.
This issue tracks that cutover and the parking + deprecation of the existing (Jekyll-rendered) ualib.org content.
Goal¶
ualib.org ~~serves the new site~~ continues to serve the old, deprecated site; the old site is preserved ("parked") and carries a prominent banner marking it deprecated and linking forward to the new site; legacy Module.Submodule.html URLs redirect to the new directory URLs.
agda-algebras.universalalgebra.org serves the new site.
Plan¶
Park the old site¶
-
Decide where to park the current live content.
Decision: keep it parked at its original and current location
ualib.org. -
Add a prominent deprecation banner to the top of the old landing page (ideally every old page): a dated notice that the site is deprecated, with a link to the new site at
agda-algebras.universalalgebra.org. A sticky<div>with a contrasting background is enough.Done in
d921a44(ongh-pages): a dated, full-bleed banner on the landing page, all 147 Jekyll content pages (via a new_includes/deprecation-banner.htmlreferenced from both page layouts), and the 198 root-levelagda --htmlcode fragments (a self-contained inline-styled bar, since those files have no<body>).
Cut over to the new site¶
- Point GitHub Pages at the
gh-pagesbranch (Settings → Pages → Deploy from a branch →gh-pages/ root). Done on the new-home repouniversalalgebra/agda-algebras. - Attach the custom domain: set
cname: agda-algebras.universalalgebra.orgin.github/workflows/docs.yml(written into theCNAMEon every deploy). - Update registrar DNS: point
agda-algebras.universalalgebra.orgat GitHub Pages, per GitHub's custom-domain docs. - ~~Populate the
mkdocs-redirectsmap (currently empty inmkdocs.yml) with the legacy flatModule.Submodule.html→ new/Module/Submodule/URLs, so external links survive.~~ Dropped — satisfied by parking: legacy URLs resolve to their original content atualib.org, and the oldBase.*tree has no equivalent on the newSetoid.*-centric site, so a redirect map would send those URLs to 404s.
Verify¶
- Spot-check at least 10 pages on the live
agda-algebras.universalalgebra.orgagainst the parked archive: content, search, inline cross-links, the/classic/agda-html mirror, and the module constellation. - Confirm HTTPS (GitHub-provisioned certificate) is active on the apex and
www. - Confirm a sample of legacy
….htmlURLs resolve — directly now (parked atualib.org), rather than via a redirect.
Acceptance criteria¶
-
https://agda-algebras.universalalgebra.orgserves the new MkDocs site over HTTPS. - The old site is parked at its original URL (
ualib.org) and shows a dated deprecation banner linking to the new site. - Legacy
Module.Submodule.htmlURLs resolve (directly or via redirect). - No regression in the currently-live content during the transition: the old site stays reachable until the new one is verified.
Related¶
- PR #427 — the new MkDocs pipeline (closes #295).
- ADR-007 (
docs/adr/007-mkdocs-rendering-pipeline.md) — records the deferred-cutover decision and the checklist this issue executes. -
295 — M10-1 rendering-pipeline modernization.¶
Notes¶
- This is the last remaining item from ADR-007's deferred-cutover checklist. It is intentionally an ops issue (Pages config + DNS + a banner), not a code change, so it can land independently once PR #427 is merged.
- The "park + banner" step is what makes the transition safe: nothing about the old content is destroyed, and visitors to stale links are routed forward.
Issue M10-5: Improve how module imports are presented on the documentation pages (#431, closed)¶
Labels: documentation, milestone-10-polish
Context¶
Every rendered module page opens with the module's full import block (open import …), plus the OPTIONS pragma and the module header, shown verbatim with no framing — no comment or heading telling the reader "these are the module's imports." To anyone who knows Agda this is obvious, but for a documentation reader (as opposed to someone reading source) it is noise up front: it pushes the actual content down the page and reads as undocumented boilerplate.
This issue is to weigh ways to make the import/scaffolding blocks less obtrusive for the casual reader without losing them for readers who want the full source (which is always available in the /classic/ agda-html mirror and on GitHub).
Options to consider¶
- (a) Always hide the scaffolding on doc pages. Strip or collapse the leading import/OPTIONS/module blocks during
mkdocs_gen_library.py(or hide them with CSS), keeping them only in/classic/and the GitHub source. Most aggressive; least reversible for a reader who does want to see them inline. - (b) Collapsible admonition. Wrap the imports in a
pymdownx.detailsblock (??? note "Module imports"), collapsed by default. Pure-Markdown, no JS — but needs each import block marked. Could be automated in gen-files (wrap the leading<pre class="Agda">blocks up to the module header in a<details>) so the 283 source files are not touched. - (c) A "Show / hide Agda" toggle, à la formal-ledger-specifications. A small JS control at the top of each page that flips "Show more Agda" / "Show less Agda", hiding/showing the scaffolding (and optionally all code) globally, with the choice persisted in
localStoragelike the theme toggle. Least lossy (reader opts in) and most flexible (can hide more than imports).
Things to work out¶
- Reliable identification of the "scaffolding" blocks. In the agda-html output these are the leading
<pre class="Agda">blocks containing theOPTIONSpragma, themodule … whereheader, and theopen import/importlines (and arguably theprivate variabledeclarations). A heuristic in gen-files or in JS can tag them. - Granularity. Just the imports, or all scaffolding (pragma + module line + private variables)? formal-ledger's toggle hides more than imports.
- Scope of the preference. Per-page state vs. a global, persisted preference.
- Interaction with existing features. The copy button (
agda-copy.js) and the token highlighting must keep working on whatever remains visible. - Nothing is lost.
/classic/and the GitHub source always show everything, so any of these is safe.
Leaning¶
Option (c) seems the best fit — it is the least lossy and the most flexible, and it matches a pattern the team already maintains on the formal-ledger site (so there is prior art to adapt). Option (b), automated in gen-files, is the simplest to ship without per-file edits and could be a good first step. Option (a) is a fallback if a toggle proves more trouble than it is worth.
Acceptance (to be refined after discussion)¶
- A casual reader's first screenful of a module page is content/prose, not a wall of imports.
- Readers who want the full source can still reach it inline (toggle) or via
/classic/and GitHub. - Highlighting and the copy button continue to work.
Related¶
- PR #427 — the MkDocs rendering pipeline.
- ADR-007 (
docs/adr/007-mkdocs-rendering-pipeline.md). - formal-ledger-specifications — the "Show more/less Agda" toggle this borrows from.
Issue M10-6: Explore definition-level dependency graphs for the documentation site (#432)¶
Labels: documentation, milestone-10-polish
Context (exploratory)¶
The site has a module-level constellation (the import graph, as a d3 force-directed graph; see docs/constellation.md). A finer-grained, definition/lemma-level dependency view — "what does Birkhoff's HSP theorem actually rest on?" — would be valuable for a proof-engineering audience in a way the module graph is not.
This is deliberately an open-ended, exploratory issue: the aim is to investigate, prototype, and discuss approaches, with loosely defined targets. No fixed deliverable is committed up front.
Candidate tooling¶
- omelkonian/agda-dependencies (
agda-deps) — a Haskell/cabal tool that emits a Graphviz (DOT) dependency graph between Agda definitions. Its cabal bounds requireAgda >= 2.8, which matches our pinned 2.8.0; it also pulls ingraphvizandfgl. - Derive it ourselves from data we already produce. The
agda --htmlpass already emits per-token hyperlinks (each identifier links to its defining site); a definition-level dependency graph might be extractable from that cross-reference data without adding a second Haskell toolchain. Worth comparing againstagda-deps. - Agda's own
--dependency-graph(module-level only — already covered by the constellation, noted for completeness).
Questions and approaches to explore¶
- Build integration. If we use
agda-deps: add it to the Nix flake (callCabal2nix, or a flake input), ideally reusing nixpkgs' Agda 2.8 Haskell library so we don't rebuild Agda-the-library from source; add thegraphvizbinary. How much does this add to CI wall-clock, and what caches it? - Granularity and legibility. A definition-level graph over 283 modules / 38k lines is a hairball as a single global picture. More legible units to try: per-theorem (an "anatomy of a proof" — e.g. the dependency cone of Birkhoff's HSP), per-module, or an interactive/filterable graph.
- Presentation. Static SVG embedded on a page? An interactive graph (like the constellation, fed from
agda-deps' DOT/JSON)? A dedicated "anatomy of a proof" page for a few flagship results, rather than a global tab? - Relationship to the constellation. These are complementary — the module forest vs. the definition trees inside one proof. Keep both? Share a visual language?
- Maintenance cost. A second pinned Haskell toolchain next to Agda is a real ongoing cost; the "derive from agda-html" route may avoid it.
Suggested first spike¶
Wire agda-deps (or the agda-html-derived approach) into the dev environment, run it over one module/theorem (Birkhoff's HSP), render the result to SVG, and eyeball whether it is illuminating at that scope. Decide next steps from there.
Loose targets / acceptance¶
- A working prototype graph for at least one flagship result.
- A short written recommendation: whether/how to integrate (global tab vs. per-page vs. a curated "anatomy of a proof" page), the build and CI cost, and the maintenance tradeoff — enough to decide whether this becomes a real feature.
Non-goals (for now)¶
- A global, all-library definition graph (the hairball).
- Committing to a specific UI before the spike.
Related¶
- The module constellation (
docs/constellation.md), PR #427, ADR-007. - omelkonian/agda-dependencies.
Issue M10-7: Self-host the remaining webfonts, and three colour tokens that miss WCAG AA (#531)¶
Labels: documentation, milestone-10-polish
Two findings from reading stylesheets/custom.css and the page source, while choosing a visual system for williamdemeo.github.io. That site is also MkDocs Material, so the fixes are the same shape in both places. Happy to open PRs for either.
1. Three external font requests, two of which the site's own CSS overrides¶
Every page currently emits, from Material's default theme.font:
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"Roboto Mono"}</style>
and custom.css line 31:
@import url("https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/juliamono.css");
But custom.css then overrides both variables (lines 73–75):
--md-code-font: "JuliaMono", "JetBrains Mono", "Fira Code", "Cascadia Code", …
--md-text-font: "InterVar", "Inter", -apple-system, BlinkMacSystemFont, …
So Roboto Mono is never selected, and Inter is served from Google while inter-latin-wght-normal.woff2 is already self-hosted under assets/fonts/. Space Grotesk, Geist (four weights) and Sora are self-hosted too — the site is most of the way there. What is left is:
theme.font: falseinmkdocs.yml, which removes the preconnect and the Google Fonts stylesheet. The--md-text-font/--md-code-fontvalues incustom.cssalready cover what those lines were providing.- Self-host JuliaMono rather than
@import-ing it from jsDelivr.
JuliaMono is the one that matters. It is the only face in that stack with the Mathematical Alphanumeric Symbols block, so it is the only one that can render 𝑨 𝓤 𝑆 𝔸 𝕏 𝒦 𝓞 𝓥. Measured against the 1,952 non-ASCII characters agda-input.el names, and a 44-character probe drawn from real Agda:
| Face | Glyphs | agda-input | Probe |
|---|---|---|---|
| JuliaMono v0.63.2 | 11,191 | 92.8% | 44/44 |
| Cascadia Code | 2,426 | 17.0% | 14/44 |
| Fira Code | 1,551 | 19.3% | 24/44 |
| JetBrains Mono | 976 | 14.7% | 21/44 |
If jsDelivr is unreachable — blocked network, corporate proxy, or the CDN simply going away — the fallbacks silently take over and every universe level and bold-script letter on the site renders in a substitute face, mid-line. The precedent is uncomfortably close to hand: williamdemeo.org loads Fira Code from cdn.rawgit.com, which shut down in 2019, so its intended monospace font has not rendered for years and nobody noticed, because nothing fails loudly.
If it is useful, scripts/python/build_fonts.py in williamdemeo/williamdemeo.github.io#70 does exactly this job and would port over nearly unchanged. It pins sources by SHA-256, subsets by Unicode block rather than by an enumerated character list, splits JuliaMono three ways by unicode-range (56 KB text / 253 KB symbols / 154 KB mathematical alphanumerics, so a page pays only for the notation it shows), and emits deterministic WOFF2.
One warning from writing it, since it would bite anyone doing this by hand: subsetting against the characters agda-input-translations names is not enough. The Agda input method inherits from Emacs' TeX method for everything it does not redefine, so ℓ, Π and the subscript digits are absent from that list and fall back mid-line. Only a browser catches it — CSS.getPlatformFontsForNode reports which face actually rasterised each run of text.
2. Three colour tokens do not clear WCAG AA as text¶
Contrast ratios computed from custom.css's own values:
| Token | Value | Ratio | Against |
|---|---|---|---|
--md-default-fg-color--lighter (light) |
#818bab |
3.29:1 | #fbfcff |
--md-default-fg-color--lighter (dark) |
#6a7197 |
3.70:1 | #15172e |
--md-accent-fg-color (light) |
#fb6a00 |
2.86:1 | #fbfcff |
AA is 4.5:1 for body text and 3:1 for large text. Material uses --md-default-fg-color--lighter for real text in several places — the footer copyright line and search-result metadata among them — and --md-accent-fg-color is the link hover colour, so it carries link text at the moment a reader is looking straight at it.
The coral needs no change in dark, where it is 7.34:1 on #0c0e1d. It is only on paper that a saturated orange cannot carry text.
Values that keep the hue and clear AA:
| Token | Now | Suggested | After |
|---|---|---|---|
--md-default-fg-color--lighter light |
#818bab |
#626b88 |
5.15:1 |
--md-default-fg-color--lighter dark |
#6a7197 |
#8189af |
5.14:1 |
--md-accent-fg-color light |
#fb6a00 |
#b34b00 |
5.22:1 |
These are the values that palette is running under on williamdemeo.github.io, where it is kept as a switchable alternative system — so the adjusted set is already checked on every build by an audit that walks every text element in both themes and composites the background up the ancestor chain.
Everything above comes from stylesheets/custom.css and the served HTML as of 2026-08-02; I was not able to run a network trace against the live site from my environment, so the request-level claims are read from the source rather than measured.
Milestone 10 Dependencies¶
M10-1 (MkDocs rendering) is the only one of the three with concrete structural prerequisites — it consumes the .lagda.md corpus produced by M1-8, the stable file tree from M2, and the prose-comment uniformity from M4. M10-2 (organization transfer) and M10-3 (nixpkgs distribution) are governance/packaging tasks with no hard upstream dependencies; their position in this milestone is thematic rather than structural.
graph TD
M1_8["M1-8: `.lagda.md` migration"]:::ext
M2_1["M2-1: Freeze Base"]:::ext
M4_1["M4-1: Style audit"]:::ext
M10_1["M10-1: MkDocs rendering"]
M10_2["M10-2: agda org transfer"]
M10_3["M10-3: nixpkgs distribution"]
M1_8 --> M10_1
M2_1 --> M10_1
M4_1 --> M10_1
classDef ext fill:#f0f0f0,stroke:#999,stroke-dasharray: 4 3,color:#555
---¶
Dependency Graph (Mermaid)¶
graph TD
subgraph "M1 — Infrastructure"
M1_1["M1-1: Agda 2.8 / stdlib 2.3"]
M1_2["M1-2: GitHub Actions CI"]
M1_3["M1-3: Community files"]
M1_4["M1-4: STYLE_GUIDE.md"]
M1_5["M1-5: README / Preface"]
M1_6["M1-6: docs/adr/"]
M1_8["M1-8: .lagda.md migration"]
end
subgraph "M2 — Consolidation"
M2_1["M2-1: Freeze Base"]
M2_2["M2-2: Consolidate Base.Structures"]
M2_3["M2-3: Remove Graphs0"]
M2_4["M2-4: Canonical HSP"]
end
subgraph "M3 — Classical structures"
M3_1["M3-1: Classical/ scaffold"]
M3_2["M3-2: Semigroup"]
M3_3["M3-3: Stdlib bridges"]
M3_4["M3-4: Monoid / Group"]
M3_5["M3-5: Lattice"]
M3_6["M3-6: Ring"]
M3_7["M3-7: Examples"]
end
subgraph "M4 — Style sweep"
M4_1["M4-1: Style audit"]
M4_2["M4-2: Docstrings"]
M4_3["M4-3: 𝓞/𝓥 scope"]
end
subgraph "M5 — Cubical"
M5_1["M5-1: Cubical Algebra + SIP + Monoid"]
end
subgraph "M6 — FLRP"
M6_1["M6-1: Con(A) lattice"]
M6_2["M6-2: Subdirect products"]
M6_3["M6-3: Maltsev conditions"]
end
subgraph "M7 — CSP (finite)"
M7_1["M7-1: Complexity / CSP"]
end
subgraph "M8 — LLM corpus"
M8_1["M8-1: Corpus artifact"]
M8_2["M8-2: agda-native-air"]
end
subgraph "M9 — Continuous-relation apps"
M9_1["M9-1: Scott-continuous relations"]
M9_2["M9-2: Infinitary CSP"]
M9_3["M9-3: Coalgebra exploration"]
end
subgraph "M10 — Post-3.0 polish"
M10_1["M10-1: MkDocs rendering"]
M10_2["M10-2: agda org transfer"]
M10_3["M10-3: nixpkgs distribution"]
end
%% M1 internal
M1_1 --> M1_2
M1_1 --> M1_3
M1_1 --> M1_4
M1_1 --> M1_6
M1_1 --> M1_5
M1_2 --> M1_5
M1_3 --> M1_5
M1_4 --> M1_5
%% M2 depends on M1
M1_1 --> M2_1
M2_1 --> M2_2
M2_1 --> M2_3
M2_1 --> M2_4
M2_1 --> M1_5
%% M3 depends on M2
M2_1 --> M3_1
M3_1 --> M3_2
M3_2 --> M3_3
M3_2 --> M3_4
M3_3 --> M3_5
M3_4 --> M3_5
M3_4 --> M3_6
M3_2 --> M3_7
M3_4 --> M3_7
M3_5 --> M3_7
%% M4 depends on M1-4
M1_4 --> M4_1
M1_4 --> M4_2
M1_4 --> M4_3
%% M5 depends on M1 and M3-4
M1_1 --> M5_1
M3_4 --> M5_1
%% M6 depends on M3-5
M3_5 --> M6_1
M6_1 --> M6_2
M6_1 --> M6_3
%% M7 depends on M2-1 and M3-5
M2_1 --> M7_1
M3_5 --> M7_1
%% M8 depends on M4
M4_1 --> M8_1
M4_2 --> M8_1
M8_1 --> M8_2
%% M9 depends on M2-1 and M3-1; M9-2 benefits from M7-1
M2_1 --> M9_1
M2_1 --> M9_2
M3_1 --> M9_1
M3_1 --> M9_2
M7_1 -.-> M9_2
%% M10 depends on M1-8, M2-1, M4-1 (M10-1 specifically; M10-2 and M10-3 are independent)
M1_8 --> M10_1
M2_1 --> M10_1
M4_1 --> M10_1
How to Create This Project on GitHub¶
Use the companion script gh_project_populate.py (patched as described in the project planning notes to read labels from the ## Labels section above).
Prerequisites¶
- Python 3.8+.
ghCLI installed and authenticated.- The
ualib/agda-algebrasrepo must already exist.
Quick start¶
# 1. Dry run — see what would be created:
python3 scripts/python/gh_project_populate.py docs/GITHUB_PROJECT.md --repo ualib/agda-algebras --dry-run
# 2. Create everything (will prompt for confirmation):
python3 scripts/python/gh_project_populate.py docs/GITHUB_PROJECT.md --repo ualib/agda-algebras
# 3. Or create in stages:
python3 scripts/python/gh_project_populate.py docs/GITHUB_PROJECT.md --repo ualib/agda-algebras --labels-only
python3 scripts/python/gh_project_populate.py docs/GITHUB_PROJECT.md --repo ualib/agda-algebras --milestones-only
python3 scripts/python/gh_project_populate.py docs/GITHUB_PROJECT.md --repo ualib/agda-algebras --issues-only
# 4. Resume if interrupted (e.g. start from M3-2):
python3 scripts/python/gh_project_populate.py docs/GITHUB_PROJECT.md --repo ualib/agda-algebras --issues-only --start-from M3-2
Notes¶
- The patched
_parse_labelsreads from the## Labelssection of this file. See the companion patch file for the small diff. - Labels and milestones are idempotent — re-running skips existing ones.
- Issue titles are prefixed with
[M1-1],[M2-3], etc. for easy identification and ordering. - A 1.5-second delay between API calls avoids GitHub rate limiting (adjustable with
--delay).