Skip to content

feat(deep_causality_homology): Added homology crate - #755

Merged
marvin-hansen merged 12 commits into
deepcausality-rs:mainfrom
marvin-hansen:main
Aug 30, 2026
Merged

feat(deep_causality_homology): Added homology crate#755
marvin-hansen merged 12 commits into
deepcausality-rs:mainfrom
marvin-hansen:main

Conversation

@marvin-hansen

@marvin-hansen marvin-hansen commented Aug 30, 2026

Copy link
Copy Markdown
Member

Describe your changes

feat(deep_causality_homology): Added homology crate

The homology extracts abstract chains so the quantum crate
can use them without pulling in the entire topology crate.
The topology crate was refactored to use the chain traits
from the homology crates.

Issue ticket number and link

Code checklist before requesting a review

  • I have signed the DCO?
  • All tests are passing when running make test?
  • No errors or security vulnerabilities are reported by make check?

For details on make, please see BUILD.md

Note: The CI runs all of the above and fixing things before they hit CI speeds
up the review and merge process. Thank you.


Summary by cubic

Adds deep_causality_homology, a new crate holding the chain-complex layer (chain complex trait, homology field, mod-2 chain) so the quantum crate can use homology without depending on the topology crate's geometry.

Extracts the homology half of deep_causality_topology::ChainComplex into the new crate; geometry items (CellType, CellIter, Metric, cells, uniform_lattice_layout) move to a new CellularComplex trait with ChainComplex as a supertrait. Topology re-exports ChainComplex, HomologyField, and Gf2Chain so name imports keep compiling, but this is a breaking topology release (0.7.3 → 0.8.0): external impl ChainComplex blocks that defined geometry items no longer compile, and betti_number_over returns HomologyError.

Migration

  • Callers of cells() or uniform_lattice_layout() must import CellularComplex; deep_causality_cfd is updated.
  • Manifests pinning topology at "0.7" are repinned to "0.8": physics, cfd, algorithms, discovery.
  • widen_to_dense_i64 is now deep_causality_linear::csr_i8_to_dense_i64; deep_causality_linear bumps 0.1.1→0.1.2.

Bug fixes

  • Boundary matrices above the top grade return (0,0) so the shape contract holds, and betti_number_over no longer double-counts at usize::MAX.
  • From the split: basis vectors read via from_column, degenerate grades return shape-implied matrices, ∂∘∂=0 is documented and asserted, and a boundary-squared test that never formed its product is repaired.
  • The Lean proof (ChainCondition.lean) is now wired into the build — it was previously never type-checked.
  • utils_tests fixtures are #[doc(hidden)] across eight crates so they no longer render as public API.
  • The lattice test fixture is one const-generic lattice_quotient shared by all five lattice spaces, removing a latent torus_3 bug where one constant served as both grid size and axis count.

Written for commit 2fe7100. Summary will update on new commits.

Review in cubic

…mology crate

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
…crate

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
…eep_causality_homology

Homology was split across two crates. `deep_causality_topology` owned the concepts —
`ChainComplex`, `HomologyField`, `Gf2Chain` — and delegated every computation to
`deep_causality_linear`, which carried conversion helpers whose docstrings named
topology's boundary operators as their reason to exist. Neither crate owned the seam.

The cost landed with the QCL work. A quantum error-correcting code is a chain complex
that is not a space: `H_X` and `H_Z` are parity-check matrices with no cells, no metric
and no Hodge star. Reaching 419 lines of chain-complex machinery meant depending on
27,317 lines of geometry.

`deep_causality_homology` 0.1.0 now holds that layer: the `ChainComplex` trait over
boundary matrices alone, `HomologyField`, and `Gf2Chain<W>`. Its whole dependency set is
`deep_causality_linear` and `deep_causality_num`.

The trait splits in two. Six homology items move; the five geometry items — `CellType`,
`CellIter`, `Metric`, `cells`, `uniform_lattice_layout` — stay in topology on a new
`CellularComplex: ChainComplex` supertrait. Not named `CellComplex`, because that is a
published struct in the same crate root and Rust puts types and traits in one namespace.

`boundary_matrix` keeps `Cow<'_, CsrMatrix<i8>>`. Incidence numbers lie in {-1, 0, 1} by
construction, so `i8` is an invariant of the boundary operator rather than a storage
choice, and the trait needs no coefficient parameter.

`Gf2Chain` keeps `(degree, len)` as the identity of its chain group. `C_k = F_2^{n_k}` is
fixed by the cell count, and every operation the type offers belongs to that group rather
than to a complex. The two halves of that condition were checked in two places and raised
two different error types; `same_group` now checks both and raises one.

Four defects, found while moving:

  1. Basis orientation. `kernel_basis_gf2` allocates `zeros(cols, free.len())` and writes
     basis vector k down column k. Four docstrings said rows, and `from_row` is a
     contiguous word-slice copy that cannot read a column, so a caller following them got
     a vector of the wrong length. Adds `PackedGf2Vector::from_column` and `Gf2Chain::
     from_column`; corrects the docstrings.

  2. Degenerate grades returned an empty matrix. All three implementors now give the
     shape the dimension implies — d_0 is (0, n_0) and d_{max+1} is (n_max, 0) — so
     cols(d_k) == rows(d_{k+1}) holds at both ends. `betti_number_over` survived the old
     behaviour on `saturating_sub`; a kernel basis would not.

  3. `d . d = 0` was stated nowhere. It is now a documented law on the trait and an
     assertion in the conformance harness at every grade of every implementor, with
     coefficients widened past `i8` so a wrapped intermediate cannot read as zero.

  4. `test_boundary_matrix_squared_is_zero` asserted cols(d_2) == rows(d_1) — that is n_2
     against n_0 — which held on square_torus(2) only because that torus has four 0-cells
     and four 2-cells. Having checked a shape it returned without forming the product its
     name promises. Both repaired.

Formalization. `linear.gf2.betti_from_ranks` proved the Betti identity under a hypothesis
nothing supplied: `range d_{k+1} <= ker d_k`, which is the chain condition. Every Betti
number the workspace computed rested on an assumption written down once, as an argument
to a theorem. `lean/DeepCausalityFormal/Homology/ChainCondition.lean` discharges it:
`homology.chain.dd_zero_implies_range_le_ker` turns it into a matrix identity a test can
check, and `homology.chain.betti_from_dd_zero` restates the Betti identity over that.
Zero `sorry`. Both ids carry Rust witnesses that compute the two sides by separate
routines. See `deep_causality_homology/LEAN_HOMOLOGY.md`.

Test references are external. `openspec/notes/homology/reference/reference.py` builds ten
spaces in Python, checks its own Betti numbers against Hatcher, *Algebraic Topology*, and
imports nothing from this workspace. The crate's fixtures are an independent construction
of the same spaces checked against the same published values. RP^2 and the Klein bottle
are included because every complex the workspace shipped before this change is orientable
and torsion-free, so Q and F_2 agreed everywhere and the coefficient field was never
discriminated; beta_1(RP^2) is 0 over Q and 1 over F_2.

Verification: bazel test //... 1227/1227; clippy clean; cargo mutants over the new crate
50 mutants, 40 caught, 10 unviable, 0 survivors.

MIGRATION

`deep_causality_topology` re-exports `ChainComplex`, `HomologyField` and `Gf2Chain`, so
`use deep_causality_topology::ChainComplex` keeps working and no dependent manifest
changes. All four dependents pin version = "0.7" and pick this up untouched.

Two call sites need a one-line import change, and no re-export avoids it: a method belongs
to one trait, and calling it needs that trait in scope. Code that calls `cells()` or
`uniform_lattice_layout()` through a `ChainComplex` import must import `CellularComplex`
instead, which has `ChainComplex` as a supertrait:

    -use deep_causality_topology::ChainComplex;
    +use deep_causality_topology::CellularComplex;

Both are in `deep_causality_cfd` and are updated here. Callers of `num_cells`,
`max_dim`, `boundary_matrix`, `coboundary_matrix` and the Betti methods are unaffected.

`ChainComplex::betti_number_over` returns `Result<usize, HomologyError>` in place of
`TopologyError`. Only implementors that override it are affected; every implementor in
this workspace uses the provided body.

`widen_to_dense_i64`, previously private to topology, is now
`deep_causality_linear::csr_i8_to_dense_i64`.

Versions: deep_causality_homology 0.1.0 (new), deep_causality_linear 0.1.1 -> 0.1.2,
deep_causality_topology 0.7.3 -> 0.7.4.

Implements openspec/changes/extract-homology-crate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
`add-linear-algebra-crate` moves to `openspec/changes/archive/`, and its capabilities
become the established baseline under `openspec/specs/`: 72 requirements added across 13
new capabilities, 1 modified.

New: linear-crate-identity (4), linear-matrix-representations (6), linear-vector (6),
linear-solve (5), linear-dense-algorithms (7), linear-f2-algebra (5),
linear-integer-algebra (5), linear-scalar-contract (4), linear-tower-integration (5),
linear-hkt-composition (4), linear-consumer-migration (7),
linear-test-first-development (9), num-finite-field (5).

Modified: `neumann-poisson` already existed in `openspec/specs/`, and the change carried
it as MODIFIED rather than ADDED, so it merged instead of clobbering. The preconditioned
CG requirement is re-homed from `deep_causality_sparse` to `deep_causality_linear` —
same signature, same convergence behaviour, same iteration counts — and gains a scenario
pinning that both import paths resolve to one function while the retired crate still
re-exports it.

Eight tasks were open. Both groups are closed on evidence, and the evidence is recorded
in the archived tasks.md rather than implied by the checkmark.

Group 7, publishing, verified against the crates.io API rather than from memory:
deep_causality_linear 0.1.1 (2 versions), deep_causality_sparse 0.2.5 (13),
deep_causality_tensor 0.5.3 (24), deep_causality_topology 0.7.3 (16),
deep_causality_physics 0.8.2 (17). Zero yanked versions across all five, which closes
7.5 directly. For 7.4, published deep_causality_topology 0.7.3 carries
deep_causality_linear at req = ^0.1, resolving to the published 0.1.1; `cargo publish`
builds the tarball with path dependencies stripped, so its acceptance is the
resolve-and-compile check that task asks for.

Group 8 said "file separately", so the action was to file, not to fix. The three
findings are now in `openspec/notes/linear/FOLLOW-UPS.md`, re-verified against the tree
first — all three still hold, and one had drifted:

  - deep_causality_physics `invert_3x3` (gr_utils.rs:114) and `inverse_spatial_metric`
    (adm_state.rs:126) reject a singular spatial metric at 1e-14 and 1e-12, a factor of
    100 apart, and the second compares in f64 — lossy for Float106, the extended
    carrier the ADM state can be instantiated at.
  - `CausalMultiField::inverse` documents "Uses matrix inverse for each cell" and maps
    the multivector reversion inverse instead.
  - `CausalTensor::matmul` is over-bounded on PartialOrd. The cited path had moved to
    ops/tensor_product/mod.rs:13, and the same over-bound also sits on the trait method
    at api/mod.rs:35 — which the original note missed. Matrix multiplication needs no
    ordering, and the bound excludes the complex numbers, quaternions and octonions,
    all of which are Ring.

None of the three is fixed here, and the note says so.

Archiving invalidated three references to the pre-archive path, all repointed:

  - `extract-homology-crate/proposal.md` justified its empty Modified Capabilities with
    "the linear crate's specs remain under the unarchived add-linear-algebra-crate
    change", which stopped being true. The reason that survives is that the promoted
    linear-* specs describe the matrix and elimination layer the homology crate
    consumes, not the chain complex it defines over them.
  - `openspec/notes/linear/prototype/README.md` and
    `openspec/notes/linear/deep-causality-linear.md` pointed at the live change
    directory.

Also ignores `__pycache__/`, produced by running the reference oracles under
`openspec/notes/*/reference/`.

`openspec validate extract-homology-crate` passes. No source file is touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
`extract-homology-crate` moves to `openspec/changes/archive/`, and its three capabilities
become the baseline under `openspec/specs/`: 15 requirements, 39 scenarios, no collisions
with existing specs and nothing modified.

  homology-chain-complex       5 requirements, 13 scenarios
  homology-gf2-chain           5 requirements, 14 scenarios
  topology-cell-complex-seam   5 requirements, 12 scenarios

One requirement was wrong and is corrected before promotion. `topology-cell-complex-seam`
carried "Existing consumers compile without an edit", with a scenario asserting dependents
build with "no edit to any `use` statement". Implementation disproved that: a re-export
carries a name and cannot carry a method to a trait that no longer owns it, so code
calling `cells` or `uniform_lattice_layout` through a `ChainComplex` import must name
`CellularComplex`. The proposal and tasks were corrected when the build caught it; the
spec was not, and archiving would have installed a guarantee the code does not make.

It now states the real boundary. A consumer of the homology half — `num_cells`, `max_dim`,
`boundary_matrix`, `coboundary_matrix`, `betti_number`, `betti_number_over` — compiles
with no edit at all. A consumer of a geometry method needs the owning trait named, and
that one import line is sufficient: no call site, signature or bound changes.
The measured split is recorded with it: eighteen `num_cells` sites and every
`deep_causality_physics` file untouched, two sites in `deep_causality_cfd` needing the
import.

Task 10.7 closes with what happened rather than a bare checkmark: the commit message was
prepared and handed over, and committed by the author as 5d591e9.

Repoints every reference to the notes trees that moved to `openspec/notes/archive/`.
Twenty files carried a dead path — four in the specs and changes archived here and in
8154e98, twelve in `deep_causality_linear` and `deep_causality_homology` sources and
tests, and the rest in `deep_causality_sparse` and the mathematics examples. All are
comments, docstrings and prose; `cargo check` over the three affected crates is clean.
`openspec/notes/linear/HKT-LAW-FINDINGS.md` is the one exception to the mapping — it went
to `openspec/notes/unified_math/`, not the archive, and is repointed there.

No source behaviour changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
`extract-homology-crate` moves to `openspec/changes/archive/`, and its three capabilities
become the baseline under `openspec/specs/`: 15 requirements, 39 scenarios, no collisions
with existing specs and nothing modified.

  homology-chain-complex       5 requirements, 13 scenarios
  homology-gf2-chain           5 requirements, 14 scenarios
  topology-cell-complex-seam   5 requirements, 12 scenarios

One requirement was wrong and is corrected before promotion. `topology-cell-complex-seam`
carried "Existing consumers compile without an edit", with a scenario asserting dependents
build with "no edit to any `use` statement". Implementation disproved that: a re-export
carries a name and cannot carry a method to a trait that no longer owns it, so code
calling `cells` or `uniform_lattice_layout` through a `ChainComplex` import must name
`CellularComplex`. The proposal and tasks were corrected when the build caught it; the
spec was not, and archiving would have installed a guarantee the code does not make.

It now states the real boundary. A consumer of the homology half — `num_cells`, `max_dim`,
`boundary_matrix`, `coboundary_matrix`, `betti_number`, `betti_number_over` — compiles
with no edit at all. A consumer of a geometry method needs the owning trait named, and
that one import line is sufficient: no call site, signature or bound changes.
The measured split is recorded with it: eighteen `num_cells` sites and every
`deep_causality_physics` file untouched, two sites in `deep_causality_cfd` needing the
import.

Task 10.7 closes with what happened rather than a bare checkmark: the commit message was
prepared and handed over, and committed by the author as 5d591e9.

Repoints every reference to the notes trees that moved to `openspec/notes/archive/`.
Twenty files carried a dead path — four in the specs and changes archived here and in
8154e98, twelve in `deep_causality_linear` and `deep_causality_homology` sources and
tests, and the rest in `deep_causality_sparse` and the mathematics examples. All are
comments, docstrings and prose; `cargo check` over the three affected crates is clean.
`openspec/notes/linear/HKT-LAW-FINDINGS.md` is the one exception to the mapping — it went
to `openspec/notes/unified_math/`, not the archive, and is repointed there.

No source behaviour changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
@marvin-hansen marvin-hansen self-assigned this Aug 30, 2026
@codecov

codecov Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.92183% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.23%. Comparing base (d9d0b48) to head (2fe7100).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
deep_causality_homology/src/types/gf2_chain/mod.rs 96.15% 3 Missing ⚠️
...ausality_homology/src/errors/homology_error/mod.rs 92.85% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main     #755    +/-   ##
========================================
  Coverage   97.22%   97.23%            
========================================
  Files        1319     1322     +3     
  Lines       77875    78121   +246     
========================================
+ Hits        75716    75959   +243     
- Misses       2159     2162     +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 199 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lean/BUILD.bazel">

<violation number="1" location="lean/BUILD.bazel:44">
P2: The new Homology namespace is registered for the Bazel gate but the root aggregator lean/DeepCausalityFormal.lean does not import DeepCausalityFormal.Homology.ChainCondition, while it imports every other namespace's files. CI (formalization.yml) runs only `lake build`, which builds the DeepCausalityFormal root module and its imports, so this proof is never type-checked by the actual CI gate. Add `import DeepCausalityFormal.Homology.ChainCondition` to the root aggregator.</violation>
</file>

<file name="openspec/specs/num-finite-field/spec.md">

<violation number="1" location="openspec/specs/num-finite-field/spec.md:49">
P2: The motivating claim that the three multivector sites 'sit under a `Field` bound' today is stale: in the current tree all three (`commutator_geometric`, `to_coefficients`, `commutator_geometric_impl`) are already bounded on `DivisibleByIntegers`, with doc comments that restate this spec. The cited line numbers (mod.rs:163, conversions.rs:139, ops_product_impl.rs:316) also no longer match where the `T::one() + T::one()` terms live (181, 145, 326). Update the present-tense problem statement and citations to the current code so the spec doesn't misrepresent what still needs migrating.</violation>
</file>

<file name="openspec/specs/linear-consumer-migration/spec.md">

<violation number="1" location="openspec/specs/linear-consumer-migration/spec.md:102">
P3: The file counts are stale: the literal currently appears in 129 files, with 44 under openspec/changes/archive/, not 203 and 34. Refresh the numbers so the requirement and its archive-touchstone rationale match the tree.</violation>
</file>

<file name="deep_causality_topology/src/types/manifold/mod.rs">

<violation number="1" location="deep_causality_topology/src/types/manifold/mod.rs:48">
P2: This bound rejects chain-only `K` types, but the module, README, and HKT documentation still promise `K: ChainComplex`. Update those public descriptions to require `CellularComplex` and explain the narrower API.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread deep_causality_topology/src/types/gf2_chain/mod.rs
Comment thread deep_causality_topology/src/traits/chain_complex.rs
Comment thread deep_causality_topology/src/types/neighborhood/coface_adjacent.rs Outdated
Comment thread deep_causality_topology/src/types/neighborhood/face_adjacent.rs Outdated
Comment thread deep_causality_topology/src/traits/neighborhood.rs Outdated
Comment thread openspec/notes/unified_math/unified_math_gaps.md Outdated
Comment thread openspec/specs/neumann-poisson/spec.md Outdated
Comment thread openspec/specs/linear-crate-identity/spec.md Outdated
… and 42 review findings

Code review raised 35 findings against the homology extraction and the specs it promoted. Each was
verified against the tree before any edit; 34 confirmed, 8 confirmed with a wrong detail, none
refuted. Every reviewer claim held up in substance.

BREAKING: deep_causality_topology 0.7.4 -> 0.8.0

The published 0.7.3 `ChainComplex` carried six geometry items and returned `TopologyError`. The
extraction removed the geometry items, moved them to `CellularComplex`, and changed the error type
to `HomologyError` — then shipped that as a patch. `git show 5d591e9^` has the old trait.

A re-export carries a name, not a trait's contents, so this breaks:

  - an external `impl ChainComplex for MyType` defining `CellType`, `CellIter`, `Metric`, `cells`
    or `uniform_lattice_layout` now fails with E0437,
  - a `K: ChainComplex` bound naming `K::CellType` or calling `k.cells(..)` no longer resolves,
  - `betti_number_over` returns a different error type.

All three re-export shims said the old import path kept working. They now carry a
`# This is a breaking change` section naming what moved and what a caller does about it. Four
in-workspace manifests pinned topology at "0.7" and would have failed to resolve; physics, cfd,
algorithms and discovery are repinned to "0.8".

CODE

- `Neighborhood`, `FaceAdjacent` and `CofaceAdjacent` go back to a `ChainComplex` bound. An
  automated pass widened them to `CellularComplex` during the split, but the bodies touch only
  `max_dim` and the boundary and coboundary matrices, so the wider bound excluded abstract complexes
  for nothing.
- `LatticeComplex::boundary_matrix` returned `num_cells(D)` rows at every grade above the top, not
  only at `D + 1`, so `cols(∂_{D+1}) == rows(∂_{D+2})` was false. Grades past `D + 1` now return
  `(0, 0)`. The conformance harness did not reach above `max_dim + 1`; it does now, and the fix was
  temporarily reverted to confirm the widened harness fails without it.
- `ChainComplex::betti_number_over` stepped the grade with `saturating_add(1)`, so at
  `k == usize::MAX` it re-read `∂_MAX` and subtracted its rank twice. It steps with `checked_add`
  and takes a next-boundary rank of zero at the ceiling.
- `reference_spaces()` covered nine of the oracle's ten spaces. `T³` is added, gated
  `#[cfg(not(miri))]`: at 702 simplices against the next-largest 96 it takes 50 seconds to build
  under Miri against 2 milliseconds native, so `make miri` skips it the way other crates skip their
  slow suites.

FORMALIZATION

`lean/DeepCausalityFormal.lean` imported ten namespaces and not `Homology`, so
`Homology/ChainCondition.lean` was reachable from no built module. CI runs `lake build`, which
builds the root and its imports, so the proof was never type-checked by the gate that was supposed
to check it. The Bazel target passed and the CI gate was hollow.

The header's two module lists also omitted `Homology`, `Rational` and `Quantum` while importing all
three; all are described now, and the lists are verified against the imports.

`ChainCondition.lean` is warning-clean. Chasing the linter shrank the proof: `Matrix.mulVecLin_mul`
is already a `simp` lemma, so the `have` bridging the composite was doing nothing and `simp [h]`
closes the goal alone. `Homology` is renamed `HomologyGroup`, since inside namespace
`DeepCausalityFormal.Homology.ChainCondition` the old name produced a duplicated path.

`reference.py` returned `(0, 0)` for the top degenerate grade where `d_{max+1}` has one row per
maximal cell, contradicting the file's own emitted shape table and the contract the Rust crate
implements. Pasting those shapes into the conformance suite would have pinned the wrong top-grade
shape. `betti()` also selected 𝔽₂ for any field name that was not exactly `Q`, so a typo silently
computed over the wrong field; unknown names are now rejected.

TEST FIXTURES ARE HIDDEN FROM THE DOCUMENTED SURFACE

`utils_tests` must be `pub` because Bazel cannot reach the `tests` tree from a test target. It does
not have to be documented. Eight crates rendered it on docs.rs as public API: algebra, haft, linear,
num_complex, physics, topology, ultragraph and tensor. All are `#[doc(hidden)]` now, joining
homology, which already was.

Two of them needed more than the attribute. A public function in `cell_splitting.rs` linked into
the module, and rustdoc renders a hidden module when public documentation points into it. Haft's
crate-level doc advertised `utils_tests` in a hand-written module tour, which no attribute affects.

Verified by rendering: `utils_tests` appears on none of the nine crate indexes, and `axis_mask`
is still documented at its real public path.

SPECS

Eleven promoted specs and three archived-change documents described a pre-refactor tree. Corrections
include: a cited source path in a retired crate; a baseline witness credited with `Monad` and
`Adjunction` that it deliberately does not implement; a "two marker impls away" ring gap that is
already closed, where following the spec would have produced an E0119 duplicate impl; hardware-tied
benchmark ratios standing as normative pass/fail gates with no bench target to reproduce them; a
justification citing an `svd()` call and a `1e-5` threshold that exist nowhere in the tree; scope
arithmetic that summed to 14 and 17 where the text said 13 and 16; a conjugate-linearity scenario
whose assertions any symmetric form satisfies; a `TBD` placeholder; and stale file counts,
recounted.

Two claims about this change's own specs were also wrong and are fixed in both the archived and
promoted copies: `deep_causality_algebra` was listed in a dependency set that holds two crates, and
a scenario required the row-oriented basis path to be absent or to report a mismatch when it is
public and silently returns a different length.

`linear-vector` claimed length mismatches fail with a typed error rather than panicking. The
checked `add`, `sub` and `dot` do return errors; `core::ops::Add` fixes `type Output = Self` and has
no error channel, so it asserts. Both paths are stated.

Four relative links were broken by the notes move and are repointed.

VERIFICATION

bazel test //... — 1227/1227. clippy --workspace --all-targets — 0. fmt --check — clean.
cargo doc --workspace — 0 errors. openspec validate --specs — 172/172.
bazel test //lean:Homology --nocache_test_results — passes, 0 sorry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 58 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread deep_causality_homology/src/utils_tests/mod.rs Outdated
Comment thread deep_causality_homology/src/traits/chain_complex.rs Outdated
Comment thread openspec/notes/quantum/qcl-gaps.md Outdated
Comment thread openspec/specs/linear-f2-algebra/spec.md Outdated
Comment thread openspec/specs/linear-dense-algorithms/spec.md Outdated
…our stale references

A second review pass over the homology work raised five findings. All five were verified against
the tree before any edit and all five held.

THE LATTICE FIXTURE IS NOW ONE IMPLEMENTATION

`torus_3` carried its own facet-generation and validation pipeline because `lattice_quotient` was
written for two dimensions. `lattice_quotient` is const-generic over `D` now, and all five lattice
fixtures are one call each:

    lattice_quotient("torus_2", [3, 3],    |[x, y]|    [x % 3, y % 3])
    lattice_quotient("torus_3", [3, 3, 3], |[x, y, z]| [x % 3, y % 3, z % 3])

`[usize; D]` rather than slices, because the call sites decide it. Arrays let the gluing closures
destructure, so coordinates keep their names and the Klein-bottle and Mobius closures stay the
one-liners they were. A `&[usize] -> Vec<usize>` signature would have made them
`|p| vec![p[0] % 3, p[1] % 3]`: unnamed coordinates, a heap allocation per lattice point, and an
arity mistake that panics at run time instead of failing to compile.

The axis-order enumeration replaces a `filter(|[a, b, c]| a != b && b != c && a != c)` that only
worked at three axes. The degeneracy assertion is kept at every dimension rather than adopting
reference.py's `if len(s) == dim + 1`, which drops a folded simplex silently; the Rust fixture is
now stricter than the Python oracle on that point.

This also removes a latent bug. The old `torus_3` used one constant for both the grid size and the
axis count, so a 4x4x4 torus would have generated 24 index triples over `0..4` and panicked
incrementing a corner. `sizes: [usize; D]` separates the two roles.

The refactor is behaviour-preserving, and that is measured rather than inferred. Every non-zero
boundary-matrix entry, with its sign and position, at every grade of all ten fixtures, is identical
before and after: the fixture module was swapped back to its previous revision, fingerprinted, and
diffed. The vertex labels did not move either, `torus_3` included, because the mixed-radix fold
reduces to the base the old code hardcoded.

FOUR STALE REFERENCES

- `chain_complex.rs` carried the `usize::MAX` boundary-case comment twice, pasted verbatim. One copy
  remains.
- `qcl-gaps.md` cited the three topology re-export shims at lines 22, 15 and 15. The `pub use`
  statements are at 38, 25 and 27; the old numbers landed a reader in doc-comment prose. The file
  was swept for recurrences and has none.
- `linear-f2-algebra` pinned the same re-export to `homology_field/mod.rs:15`, also a doc comment.
  Now `:25`.
- `linear-dense-algorithms` said both determinant sites are fed "matrices the diagonal cannot
  pivot". That is true of one. The Cayley-Menger matrix has a zero diagonal end to end: the buffer
  starts at zero, `one` is written only into `1..matrix_dim`, and every remaining diagonal entry is
  a vertex's squared distance to itself. The Gram matrix's diagonal holds squared edge-vector
  norms, positive whenever the vertices are distinct and zero only when one repeats, so it is
  usable but poorly scaled. The replaced `gaussian_determinant` tested it against an absolute
  floor, which read a uniformly small simplex as degenerate for being small; the shared
  `determinant` scales its floor by the matrix's own magnitude. The two sites are now described
  separately.

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
@marvin-hansen
marvin-hansen merged commit 8d5b025 into deepcausality-rs:main Aug 30, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant