Skip to content

Commit 9098ff2

Browse files
afflomclaude
andcommitted
Bump version to 0.4.15
Wire ψ_1 Recurse expansion per wiki ADR-057 step 3. Foundation's `primitive_simplicial_nerve_betti<T>` previously treated `ConstraintRef::Recurse` entries as opaque anonymous Sites with all-sites support — the structural-typing-at-the-constraint-geometry property declared by ADR-057 was unrealized in evaluation. v0.4.15 adds: - `primitive_simplicial_nerve_betti_in<T, R>` — registry-parameterized variant that walks `T::CONSTRAINTS`, expands `Recurse { shape_iri, descent_bound }` entries through `lookup_shape_in::<R>(iri)` with bounded descent, and computes N(C) on the flattened constraint set. - `primitive_simplicial_nerve_betti<T>` — now delegates to the `_in` variant with `EmptyShapeRegistry` (foundation built-in registry only) and returns `RECURSE_SHAPE_UNREGISTERED` on unknown shapes. - `primitive_cartesian_nerve_betti_in<S, R>` — registry-aware Künneth companion for `CartesianProductShape` inputs. - `expand_constraints_in<R>` — the underlying flattening walker. - `constraint_site_support_mask_of` — slice-based site-support computation on a `&ConstraintRef` (used after expansion). - `ResolverTuple::ShapeRegistry` associated type — `NullResolverTuple` defaults to `EmptyShapeRegistry`; the SDK `resolver!` macro admits a `shape_registry: MyRegistry` clause that binds the application's `register_shape!`-emitted marker. Behavioral tests prove N(C) reflects the expanded grammar (different Betti profile for the same `Recurse` entry with/without a populated registry), and validate the zero-bound bottom-out plus the unknown-shape error propagation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 48aebd1 commit 9098ff2

17 files changed

Lines changed: 703 additions & 39 deletions

Cargo.lock

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ members = [
1818
resolver = "2"
1919

2020
[workspace.package]
21-
version = "0.4.14"
21+
version = "0.4.15"
2222
edition = "2021"
2323
rust-version = "1.83"
2424
license = "Apache-2.0"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ structure based on Z/(2^n)Z.
99

1010
## Ontology
1111

12-
Version 0.4.14: 34 namespaces · 474 classes · 948 properties · 3601 named individuals
12+
Version 0.4.15: 34 namespaces · 474 classes · 948 properties · 3601 named individuals
1313

1414
All terms are encoded as typed Rust data in `spec/` (`uor-ontology`) and exported as:
1515
- `foundation/` (`uor-foundation`) — typed Rust traits (published to crates.io)

codegen/src/enforcement.rs

Lines changed: 141 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7559,19 +7559,70 @@ fn emit_phase_j_primitives(f: &mut RustFile) {
75597559
f.doc_comment("differently-shaped complex than the caller asked about. Callers propagate");
75607560
f.doc_comment("the witness via `?` (pattern mirrored on `primitive_terminal_reduction`).");
75617561
f.doc_comment("");
7562+
f.doc_comment("ADR-057: `T::CONSTRAINTS` may contain `ConstraintRef::Recurse` entries");
7563+
f.doc_comment("referencing shapes by IRI. This primitive expands Recurse references");
7564+
f.doc_comment("through the **foundation built-in shape-IRI registry** (`lookup_shape`),");
7565+
f.doc_comment("decrementing the descent budget on each Recurse encountered and");
7566+
f.doc_comment("terminating when the budget reaches zero. Applications that register");
7567+
f.doc_comment("their own shapes (via the SDK `register_shape!` macro) use");
7568+
f.doc_comment("[`primitive_simplicial_nerve_betti_in`] which is generic over the");
7569+
f.doc_comment("application's `ShapeRegistryProvider`. The structural reading at ψ_1");
7570+
f.doc_comment("reflects the expanded constraint geometry — Recurse entries are not");
7571+
f.doc_comment("opaque anonymous Sites but their structurally-substituted body per the");
7572+
f.doc_comment("registered shape's `CONSTRAINTS` array.");
7573+
f.doc_comment("");
75627574
f.doc_comment("# Errors");
75637575
f.doc_comment("");
7564-
f.doc_comment("Returns `NERVE_CAPACITY_EXCEEDED` when either cap is exceeded.");
7576+
f.doc_comment("Returns `NERVE_CAPACITY_EXCEEDED` when either cap is exceeded after");
7577+
f.doc_comment("expansion. Returns `RECURSE_SHAPE_UNREGISTERED` when a `Recurse`");
7578+
f.doc_comment("entry references an IRI not present in the consulted registry");
7579+
f.doc_comment("(non-zero descent budget).");
75657580
f.line("pub fn primitive_simplicial_nerve_betti<T: crate::pipeline::ConstrainedTypeShape + ?Sized>() -> Result<[u32; MAX_BETTI_DIMENSION], GenericImpossibilityWitness> {");
7566-
f.line(" let k_all = T::CONSTRAINTS.len();");
7567-
f.line(" if k_all > NERVE_CONSTRAINTS_CAP {");
7581+
f.line(" // ADR-057: foundation-default registry path. EmptyShapeRegistry's");
7582+
f.line(" // REGISTRY is the empty slice, so lookup_shape_in falls through to");
7583+
f.line(" // foundation's built-in FOUNDATION_REGISTRY (the canonical stdlib path).");
7584+
f.line(" primitive_simplicial_nerve_betti_in::<T, crate::pipeline::shape_iri_registry::EmptyShapeRegistry>()");
7585+
f.line("}");
7586+
f.blank();
7587+
f.doc_comment("ADR-057: registry-parameterized variant of");
7588+
f.doc_comment("[`primitive_simplicial_nerve_betti`]. Walks `T::CONSTRAINTS` and expands");
7589+
f.doc_comment("every `ConstraintRef::Recurse { shape_iri, descent_bound }` entry by");
7590+
f.doc_comment("looking up `shape_iri` through `R`'s registry plus foundation's");
7591+
f.doc_comment("built-in registry, decrementing the descent budget on each recursive");
7592+
f.doc_comment("walk, and terminating when the budget reaches zero. The expanded");
7593+
f.doc_comment("constraint sequence is the input to the nerve computation — the");
7594+
f.doc_comment("structural reading at ψ_1 reflects the recursive grammar.");
7595+
f.doc_comment("");
7596+
f.doc_comment("This is the entry point ψ_1 `NerveResolver` impls call from the");
7597+
f.doc_comment("application's resolver-tuple — `R` is the ResolverTuple's");
7598+
f.doc_comment("`ShapeRegistry` associated type per ADR-036+ADR-057.");
7599+
f.doc_comment("");
7600+
f.doc_comment("# Errors");
7601+
f.doc_comment("");
7602+
f.doc_comment("Returns `NERVE_CAPACITY_EXCEEDED` when the expanded constraint set");
7603+
f.doc_comment("exceeds `NERVE_CONSTRAINTS_CAP` or `NERVE_SITES_CAP`. Returns");
7604+
f.doc_comment("`RECURSE_SHAPE_UNREGISTERED` when a `Recurse` entry references an");
7605+
f.doc_comment("IRI not present in either `R::REGISTRY` or foundation's built-in.");
7606+
f.line("pub fn primitive_simplicial_nerve_betti_in<");
7607+
f.line(" T: crate::pipeline::ConstrainedTypeShape + ?Sized,");
7608+
f.line(" R: crate::pipeline::shape_iri_registry::ShapeRegistryProvider,");
7609+
f.line(">() -> Result<[u32; MAX_BETTI_DIMENSION], GenericImpossibilityWitness> {");
7610+
f.line(" // ADR-057 step 3: expand T::CONSTRAINTS, walking ConstraintRef::Recurse");
7611+
f.line(" // through R's registry with bounded descent.");
7612+
f.line(" let mut expanded: [crate::pipeline::ConstraintRef; NERVE_CONSTRAINTS_CAP] =");
7613+
f.line(
7614+
" [crate::pipeline::ConstraintRef::Site { position: 0 }; NERVE_CONSTRAINTS_CAP];",
7615+
);
7616+
f.line(" let mut n_expanded: usize = 0;");
7617+
f.line(" expand_constraints_in::<R>(T::CONSTRAINTS, u32::MAX, &mut expanded, &mut n_expanded)?;");
7618+
f.line(" let n_constraints = n_expanded;");
7619+
f.line(" if n_constraints > NERVE_CONSTRAINTS_CAP {");
75687620
f.line(" return Err(GenericImpossibilityWitness::for_identity(\"NERVE_CAPACITY_EXCEEDED\"));");
75697621
f.line(" }");
75707622
f.line(" let s_all = T::SITE_COUNT;");
75717623
f.line(" if s_all > NERVE_SITES_CAP {");
75727624
f.line(" return Err(GenericImpossibilityWitness::for_identity(\"NERVE_CAPACITY_EXCEEDED\"));");
75737625
f.line(" }");
7574-
f.line(" let n_constraints = k_all;");
75757626
f.line(" let n_sites = s_all;");
75767627
f.line(" let mut out = [0u32; MAX_BETTI_DIMENSION];");
75777628
f.line(" if n_constraints == 0 {");
@@ -7582,7 +7633,7 @@ fn emit_phase_j_primitives(f: &mut RustFile) {
75827633
f.line(" let mut support = [0u16; NERVE_CONSTRAINTS_CAP];");
75837634
f.line(" let mut c = 0;");
75847635
f.line(" while c < n_constraints {");
7585-
f.line(" support[c] = constraint_site_support_mask::<T>(c, n_sites);");
7636+
f.line(" support[c] = constraint_site_support_mask_of(&expanded[c], n_sites);");
75867637
f.line(" c += 1;");
75877638
f.line(" }");
75887639
f.line(" // Enumerate 1-simplices: pairs (i,j) with i<j and support[i] & support[j] != 0.");
@@ -7668,6 +7719,78 @@ fn emit_phase_j_primitives(f: &mut RustFile) {
76687719
f.line(" Ok(out)");
76697720
f.line("}");
76707721
f.blank();
7722+
7723+
// ── ADR-057: Recurse expansion helper ─────────────────────────────────
7724+
f.doc_comment("ADR-057 step 3: walk `in_constraints`, copying non-Recurse entries into");
7725+
f.doc_comment("`out_arr` and expanding every `ConstraintRef::Recurse { shape_iri,");
7726+
f.doc_comment("descent_bound }` by looking up `shape_iri` through `R`'s registry plus");
7727+
f.doc_comment("foundation's built-in registry and recursing into the referenced shape's");
7728+
f.doc_comment("`CONSTRAINTS`. The effective descent budget at each Recurse is the min");
7729+
f.doc_comment("of the caller's `descent_remaining` and the constraint's own");
7730+
f.doc_comment("`descent_bound`; on Recurse the budget decrements by 1 before recursion.");
7731+
f.doc_comment("A budget of 0 terminates the descent (the Recurse contributes no");
7732+
f.doc_comment("further constraints — the recursion bottoms out).");
7733+
f.doc_comment("");
7734+
f.doc_comment("# Errors");
7735+
f.doc_comment("");
7736+
f.doc_comment("Returns `NERVE_CAPACITY_EXCEEDED` when the expansion would exceed");
7737+
f.doc_comment("`NERVE_CONSTRAINTS_CAP`. Returns `RECURSE_SHAPE_UNREGISTERED` when a");
7738+
f.doc_comment("`Recurse` entry with non-zero effective budget references an IRI not");
7739+
f.doc_comment("present in either `R::REGISTRY` or foundation's built-in registry.");
7740+
f.line(
7741+
"pub fn expand_constraints_in<R: crate::pipeline::shape_iri_registry::ShapeRegistryProvider>(",
7742+
);
7743+
f.line(" in_constraints: &[crate::pipeline::ConstraintRef],");
7744+
f.line(" descent_remaining: u32,");
7745+
f.line(" out_arr: &mut [crate::pipeline::ConstraintRef; NERVE_CONSTRAINTS_CAP],");
7746+
f.line(" out_n: &mut usize,");
7747+
f.line(") -> Result<(), GenericImpossibilityWitness> {");
7748+
f.line(" let mut i = 0;");
7749+
f.line(" while i < in_constraints.len() {");
7750+
f.line(" match in_constraints[i] {");
7751+
f.line(" crate::pipeline::ConstraintRef::Recurse { shape_iri, descent_bound } => {");
7752+
f.line(" // Effective budget = min(caller's remaining, this Recurse's bound).");
7753+
f.line(" let budget = if descent_remaining < descent_bound {");
7754+
f.line(" descent_remaining");
7755+
f.line(" } else {");
7756+
f.line(" descent_bound");
7757+
f.line(" };");
7758+
f.line(" if budget == 0 {");
7759+
f.line(" // Bottom out — contribute no further constraints.");
7760+
f.line(" } else {");
7761+
f.line(" match crate::pipeline::shape_iri_registry::lookup_shape_in::<R>(shape_iri) {");
7762+
f.line(" Some(registered) => {");
7763+
f.line(" expand_constraints_in::<R>(");
7764+
f.line(" registered.constraints,");
7765+
f.line(" budget - 1,");
7766+
f.line(" out_arr,");
7767+
f.line(" out_n,");
7768+
f.line(" )?;");
7769+
f.line(" }");
7770+
f.line(" None => {");
7771+
f.line(" return Err(GenericImpossibilityWitness::for_identity(");
7772+
f.line(" \"RECURSE_SHAPE_UNREGISTERED\",");
7773+
f.line(" ));");
7774+
f.line(" }");
7775+
f.line(" }");
7776+
f.line(" }");
7777+
f.line(" }");
7778+
f.line(" other => {");
7779+
f.line(" if *out_n >= NERVE_CONSTRAINTS_CAP {");
7780+
f.line(" return Err(GenericImpossibilityWitness::for_identity(");
7781+
f.line(" \"NERVE_CAPACITY_EXCEEDED\",");
7782+
f.line(" ));");
7783+
f.line(" }");
7784+
f.line(" out_arr[*out_n] = other;");
7785+
f.line(" *out_n += 1;");
7786+
f.line(" }");
7787+
f.line(" }");
7788+
f.line(" i += 1;");
7789+
f.line(" }");
7790+
f.line(" Ok(())");
7791+
f.line("}");
7792+
f.blank();
7793+
76717794
f.doc_comment("Phase X.4: cap on the number of constraints considered by the nerve");
76727795
f.doc_comment("primitive. Phase 1a (orphan-closure): inputs exceeding this cap are");
76737796
f.doc_comment("rejected via `NERVE_CAPACITY_EXCEEDED` (was previously silent truncation).");
@@ -7702,14 +7825,21 @@ fn emit_phase_j_primitives(f: &mut RustFile) {
77027825
f.line("pub(crate) const NERVE_RANK_MOD_P: i64 = 1_000_000_007;");
77037826
f.blank();
77047827
f.doc_comment("Phase X.4: per-constraint site-support bitmask. Returns bit `s` set iff");
7705-
f.doc_comment("constraint `c` in `T::CONSTRAINTS` touches site index `s` (`s < n_sites`).");
7828+
f.doc_comment("constraint `c` touches site index `s` (`s < n_sites`).");
77067829
f.doc_comment("`Affine { coefficients, .. }` returns the bitmask of sites whose");
77077830
f.doc_comment("coefficient is non-zero — the natural \"site support\" of the affine");
77087831
f.doc_comment("relation. Remaining non-site-local variants (Residue, Hamming, Depth,");
77097832
f.doc_comment("Bound, Conjunction, SatClauses) return an all-ones mask over `n_sites`.");
7710-
f.line("pub(crate) const fn constraint_site_support_mask<T: crate::pipeline::ConstrainedTypeShape + ?Sized>(c: usize, n_sites: usize) -> u16 {");
7833+
f.doc_comment("");
7834+
f.doc_comment("ADR-057: slice-based — operates directly on a `&ConstraintRef` rather");
7835+
f.doc_comment("than indexing a `ConstrainedTypeShape::CONSTRAINTS` slot. ψ_1 calls this");
7836+
f.doc_comment("from [`primitive_simplicial_nerve_betti_in`] after `T::CONSTRAINTS` has");
7837+
f.doc_comment("been expanded into a fixed-size array via [`expand_constraints_in`].");
7838+
f.line(
7839+
"pub(crate) const fn constraint_site_support_mask_of(c: &crate::pipeline::ConstraintRef, n_sites: usize) -> u16 {",
7840+
);
77117841
f.line(" let all_mask: u16 = if n_sites == 0 { 0 } else { (1u16 << n_sites) - 1 };");
7712-
f.line(" match &T::CONSTRAINTS[c] {");
7842+
f.line(" match c {");
77137843
f.line(" crate::pipeline::ConstraintRef::Site { position } => {");
77147844
f.line(" if n_sites == 0 { 0 } else { 1u16 << (*position as usize % n_sites) }");
77157845
f.line(" }");
@@ -7730,6 +7860,9 @@ fn emit_phase_j_primitives(f: &mut RustFile) {
77307860
f.line(" if mask == 0 { all_mask } else { mask }");
77317861
f.line(" }");
77327862
f.line(" }");
7863+
f.line(" // ADR-057: any Recurse entry left in the array means");
7864+
f.line(" // expand_constraints_in already bottomed out (descent_bound = 0).");
7865+
f.line(" // Treat it as a structural placeholder with no specific site support.");
77337866
f.line(" _ => all_mask,");
77347867
f.line(" }");
77357868
f.line("}");

0 commit comments

Comments
 (0)