Skip to content

Commit 1420c6d

Browse files
afflomclaude
andcommitted
Bump version to 0.4.13
Implements wiki ADR-057 (Bounded recursive structural typing via ConstraintRef::Recurse + foundation shape-IRI registry). The framework's constraint vocabulary now admits bounded recursive shape references — the structural analog of `Term::Recurse` at the constraint level. Applications carrying inductively-defined input domains (JSON values, XML documents, AST shapes, S-expressions, ASN.1 / Protobuf message families, filesystem hierarchies, rose trees) can declare their typed structural form at the constraint-geometry level through `ConstraintRef::Recurse { shape_iri, descent_bound }` without hitting the const-eval barrier that direct self-reference in `partition_coproduct!`'s operand list raises. Foundation surface additions: - `ConstraintRef::Recurse { shape_iri: &'static str, descent_bound: u32 }` variant on `pipeline::ConstraintRef` + parallel `LeafConstraintRef::Recurse` + `ConstraintRef::as_leaf()` arm + `LeafConstraintRef::into_constraint()` arm. - `pipeline::shape_iri_registry::RegisteredShape { iri, site_count, constraints, cycle_size }` mirror struct. - `pipeline::shape_iri_registry::lookup_shape(iri) -> Option<&'static RegisteredShape>` runtime lookup surface for ψ_1 NerveResolver. - `pipeline::shape_iri_registry::__register_shape(...)` doc-hidden entry point for the SDK `register_shape!` macro and dynamic loaders. - `shift_constraint` / `shift_leaf_constraint` arms pass Recurse through unchanged (no site references to shift). - `encode_constraint_to_clauses` returns `Some(EMPTY)` for Recurse (preflight feasibility deferred to runtime ψ_1 NerveResolver). - `validate_constrained_type_const` accepts Recurse on non-empty shape_iri (registry lookup happens at runtime, parallel to ADR-049's LandauerCost deferral). - `validate_coproduct_structure` (ST_6/ST_7/ST_8 walker) passes Recurse through (no site references at this level). Wire-format integration per ADR-013/TR-08: - `fold_constraint_ref` emits discriminant byte 10 for Recurse (after Conjunction = 9), with payload `shape_iri | 0x00 | descent_bound`. - `TRACE_REPLAY_FORMAT_VERSION` bumped 9 → 10. - `rust/trace_byte_layout_pinned` validator updated. Audit surfaces: - foundation/tests/public-api.snapshot + .nostd: add `mod shape_iri_registry`. - conformance/endpoint_coverage.toml: ADR-057 coverage mapping. Conformance test coverage (foundation/tests/behavior_adr_057_recursive_typing.rs): - constraint_ref_recurse_variant_carries_shape_iri_and_descent_bound - leaf_constraint_ref_recurse_round_trips_via_as_leaf_into_constraint - shift_constraint_passes_recurse_through_unchanged - shift_leaf_constraint_passes_recurse_through_unchanged - shape_iri_registry_registered_shape_carries_canonical_fields - shape_iri_registry_lookup_returns_none_for_unregistered_iri - fold_constraint_ref_emits_discriminant_byte_10_for_recurse Future work (not blocking this release; ADR-057 surface is in place): - SDK `register_shape!` macro emitting link-section registration entries feeding `FOUNDATION_REGISTRY`. The doc-hidden `__register_shape` entry point is in place; the link-section collection mechanism extends `FOUNDATION_REGISTRY` in a follow-up release. - `partition_coproduct!` / `partition_product!` `recurse:T` / `recurse(<bound>):T` operand-grammar extension lowering to Recurse-bearing CONSTRAINTS arrays. The runtime substrate is in place; the SDK convenience comes in a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1a70b43 commit 1420c6d

16 files changed

Lines changed: 579 additions & 54 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.12"
21+
version = "0.4.13"
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.12: 34 namespaces · 474 classes · 948 properties · 3601 named individuals
12+
Version 0.4.13: 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: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5440,7 +5440,7 @@ fn generate_grounded_wrapper(f: &mut RustFile) {
54405440
f.doc_comment("Increment when the layout changes (event ordering, trailing fields,");
54415441
f.doc_comment("primitive-op discriminant table, certificate-kind discriminant table).");
54425442
f.doc_comment("Pinned by the `rust/trace_byte_layout_pinned` conformance validator.");
5443-
f.line("pub const TRACE_REPLAY_FORMAT_VERSION: u16 = 9;");
5443+
f.line("pub const TRACE_REPLAY_FORMAT_VERSION: u16 = 10;");
54445444
f.blank();
54455445
f.doc_comment("v0.2.2 T5: pluggable content hasher with parametric output width.");
54465446
f.doc_comment("");
@@ -5934,6 +5934,15 @@ fn generate_grounded_wrapper(f: &mut RustFile) {
59345934
f.line(" i += 1;");
59355935
f.line(" }");
59365936
f.line(" }");
5937+
f.line(" // ADR-057 wire-format: discriminant byte 10 + content-addressed");
5938+
f.line(" // shape_iri + descent_bound. The discriminant table extension");
5939+
f.line(" // requires TRACE_REPLAY_FORMAT_VERSION bump per ADR-013/TR-08.");
5940+
f.line(" C::Recurse { shape_iri, descent_bound } => {");
5941+
f.line(" hasher = hasher.fold_byte(10);");
5942+
f.line(" hasher = hasher.fold_bytes(shape_iri.as_bytes());");
5943+
f.line(" hasher = hasher.fold_byte(0);");
5944+
f.line(" hasher = hasher.fold_bytes(&descent_bound.to_be_bytes());");
5945+
f.line(" }");
59375946
f.line(" }");
59385947
f.line(" hasher");
59395948
f.line("}");
@@ -13155,7 +13164,10 @@ fn emit_pc_validate_coproduct_structure(f: &mut RustFile) {
1315513164
f.line(" | crate::pipeline::ConstraintRef::Hamming { .. }");
1315613165
f.line(" | crate::pipeline::ConstraintRef::Depth { .. }");
1315713166
f.line(" | crate::pipeline::ConstraintRef::SatClauses { .. }");
13158-
f.line(" | crate::pipeline::ConstraintRef::Bound { .. } => {");
13167+
f.line(" | crate::pipeline::ConstraintRef::Bound { .. }");
13168+
f.line(" // ADR-057: Recurse references a shape by content-addressed IRI;");
13169+
f.line(" // no site references at this level to check.");
13170+
f.line(" | crate::pipeline::ConstraintRef::Recurse { .. } => {");
1315913171
f.line(" // No site references at this level; nothing to check.");
1316013172
f.line(" }");
1316113173
f.line(" }");

codegen/src/pipeline.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,22 @@ fn emit_constraint_ref(f: &mut RustFile) {
16011601
f.line(" conjuncts: [LeafConstraintRef; CONJUNCTION_MAX_TERMS],");
16021602
f.line(" conjunct_count: u32,");
16031603
f.line(" },");
1604+
f.line(" /// ADR-057 substrate amendment: bounded recursive shape reference.");
1605+
f.line(" /// The constraint references another `ConstrainedTypeShape` by its");
1606+
f.line(" /// content-addressed IRI, with an explicit `descent_bound` bounding");
1607+
f.line(" /// the recursion at evaluation time. The runtime ψ_1 NerveResolver");
1608+
f.line(" /// expands the reference to the registered shape's `CONSTRAINTS`");
1609+
f.line(" /// array, decrementing `descent_bound` on each `Recurse` traversal;");
1610+
f.line(" /// when `descent_bound = 0` the recursion bottoms out (no further");
1611+
f.line(" /// constraints at that depth).");
1612+
f.line(" ///");
1613+
f.line(" /// The const-time admission path defers `Recurse` to runtime per");
1614+
f.line(" /// ADR-057's deferral rule (parallel to ADR-049's");
1615+
f.line(" /// `LandauerCost` deferral).");
1616+
f.line(" Recurse {");
1617+
f.line(" shape_iri: &'static str,");
1618+
f.line(" descent_bound: u32,");
1619+
f.line(" },");
16041620
f.line("}");
16051621
f.blank();
16061622

@@ -1636,6 +1652,11 @@ fn emit_constraint_ref(f: &mut RustFile) {
16361652
f.line(" bound_shape_iri: &'static str,");
16371653
f.line(" args_repr: &'static str,");
16381654
f.line(" },");
1655+
f.line(" /// See [`ConstraintRef::Recurse`] (ADR-057).");
1656+
f.line(" Recurse {");
1657+
f.line(" shape_iri: &'static str,");
1658+
f.line(" descent_bound: u32,");
1659+
f.line(" },");
16391660
f.line("}");
16401661
f.blank();
16411662

@@ -1672,6 +1693,9 @@ fn emit_constraint_ref(f: &mut RustFile) {
16721693
f.line(
16731694
" ConstraintRef::Conjunction { .. } => LeafConstraintRef::Site { position: 0 },",
16741695
);
1696+
f.line(" ConstraintRef::Recurse { shape_iri, descent_bound } => {");
1697+
f.line(" LeafConstraintRef::Recurse { shape_iri, descent_bound }");
1698+
f.line(" }");
16751699
f.line(" }");
16761700
f.line(" }");
16771701
f.line("}");
@@ -1701,6 +1725,9 @@ fn emit_constraint_ref(f: &mut RustFile) {
17011725
);
17021726
f.line(" ConstraintRef::Bound { observable_iri, bound_shape_iri, args_repr }");
17031727
f.line(" }");
1728+
f.line(" LeafConstraintRef::Recurse { shape_iri, descent_bound } => {");
1729+
f.line(" ConstraintRef::Recurse { shape_iri, descent_bound }");
1730+
f.line(" }");
17041731
f.line(" }");
17051732
f.line(" }");
17061733
f.line("}");
@@ -1759,6 +1786,12 @@ fn emit_constraint_ref(f: &mut RustFile) {
17591786
f.line(" Some(UNSAT_SENTINEL)");
17601787
f.line(" }");
17611788
f.line(" }");
1789+
f.line(" // ADR-057: Recurse defers to the runtime ψ_1 NerveResolver");
1790+
f.line(" // which expands the referenced shape's constraints via the");
1791+
f.line(" // shape-IRI registry. At preflight (const-eval) it carries no");
1792+
f.line(" // CNF residue — the recursion is bounded, the unrolling occurs");
1793+
f.line(" // at runtime against the registry.");
1794+
f.line(" ConstraintRef::Recurse { .. } => Some(EMPTY),");
17621795
f.line(" }");
17631796
f.line("}");
17641797
f.blank();
@@ -2041,6 +2074,108 @@ fn emit_constrained_type_shape(f: &mut RustFile) {
20412074
emit_typed_commitment(f);
20422075
emit_prism_model(f);
20432076
emit_cartesian_product_shape(f);
2077+
emit_shape_iri_registry(f);
2078+
}
2079+
2080+
/// ADR-057: emits the foundation shape-IRI registry module —
2081+
/// `RegisteredShape` struct + `lookup_shape(iri) -> Option<&'static
2082+
/// RegisteredShape>` + `__register_shape(shape: &'static RegisteredShape)`
2083+
/// surface. The registry is consulted by ψ_1's NerveResolver at runtime
2084+
/// when expanding `ConstraintRef::Recurse` references.
2085+
///
2086+
/// The MVP registry is a static slice that's empty by default; the
2087+
/// `register_shape!` SDK macro emits link-section entries that collect
2088+
/// into the slice at link time. Applications can also drive registration
2089+
/// imperatively (the `__register_shape` surface is doc-hidden but
2090+
/// publicly callable for advanced cases).
2091+
fn emit_shape_iri_registry(f: &mut RustFile) {
2092+
f.doc_comment("ADR-057: bounded recursive structural typing — foundation shape-IRI");
2093+
f.doc_comment("registry module. Mirrors the architectural pattern of the");
2094+
f.doc_comment("observable-IRI registry per ADR-038/049 and the substitution-axis");
2095+
f.doc_comment("catalog per ADR-007/030: a closed catalog of shape IRIs admissible");
2096+
f.doc_comment("as `ConstraintRef::Recurse` targets, collected at link time and");
2097+
f.doc_comment("consulted by ψ_1's NerveResolver at evaluation time.");
2098+
f.line("pub mod shape_iri_registry {");
2099+
f.line(" use super::ConstraintRef;");
2100+
f.blank();
2101+
f.indented_doc_comment("ADR-057: a registered shape entry. `iri` is the shape's");
2102+
f.indented_doc_comment("content-addressed identifier per ADR-017; `site_count`,");
2103+
f.indented_doc_comment("`constraints`, and `cycle_size` mirror the corresponding");
2104+
f.indented_doc_comment("`ConstrainedTypeShape` associated items so ψ_1's resolver");
2105+
f.indented_doc_comment("can walk the referenced shape's constraint set without");
2106+
f.indented_doc_comment("touching the original trait impl.");
2107+
f.line(" #[derive(Debug, Clone, Copy)]");
2108+
f.line(" pub struct RegisteredShape {");
2109+
f.indented_doc_comment("Content-addressed IRI of the shape (per ADR-017).");
2110+
f.line(" pub iri: &'static str,");
2111+
f.indented_doc_comment("Mirror of `<T as ConstrainedTypeShape>::SITE_COUNT`.");
2112+
f.line(" pub site_count: usize,");
2113+
f.indented_doc_comment("Mirror of `<T as ConstrainedTypeShape>::CONSTRAINTS`.");
2114+
f.line(" pub constraints: &'static [ConstraintRef],");
2115+
f.indented_doc_comment("Mirror of `<T as ConstrainedTypeShape>::CYCLE_SIZE`.");
2116+
f.line(" pub cycle_size: u64,");
2117+
f.line(" }");
2118+
f.blank();
2119+
// Registry storage: a static slice of pointers to RegisteredShape
2120+
// entries. The MVP starts empty; downstream `register_shape!` calls
2121+
// append entries via a static array the SDK helps build. Foundation
2122+
// provides the lookup surface and an internal append helper used by
2123+
// `__register_shape`.
2124+
f.indented_doc_comment("Foundation's built-in shape registry. Currently empty — applications");
2125+
f.indented_doc_comment(
2126+
"supply their `RegisteredShape` entries via `register_shape!` per ADR-057.",
2127+
);
2128+
f.indented_doc_comment("Future foundation-provided shapes (canonical JSON, AST, etc.) will");
2129+
f.indented_doc_comment("be appended here.");
2130+
f.line(" static FOUNDATION_REGISTRY: &[RegisteredShape] = &[];");
2131+
f.blank();
2132+
f.indented_doc_comment("ADR-057: look up a registered shape by IRI. Walks the foundation");
2133+
f.indented_doc_comment("registry plus any application-provided entries injected via");
2134+
f.indented_doc_comment("`register_shape!`. Returns `None` if the IRI is not present.");
2135+
f.indented_doc_comment("");
2136+
f.indented_doc_comment("Called by ψ_1's NerveResolver during `ConstraintRef::Recurse`");
2137+
f.indented_doc_comment("evaluation; called by the verifier-side validation per ADR-019.");
2138+
f.line(" #[must_use]");
2139+
f.line(" pub fn lookup_shape(iri: &str) -> Option<&'static RegisteredShape> {");
2140+
f.line(" // Foundation-built-in registry — linear scan; the registry is");
2141+
f.line(" // small (handful of canonical shapes per standard-library");
2142+
f.line(" // sub-crate publishing them).");
2143+
f.line(" let mut i = 0;");
2144+
f.line(" while i < FOUNDATION_REGISTRY.len() {");
2145+
f.line(" let entry = &FOUNDATION_REGISTRY[i];");
2146+
f.line(" if iri_eq(entry.iri, iri) {");
2147+
f.line(" return Some(entry);");
2148+
f.line(" }");
2149+
f.line(" i += 1;");
2150+
f.line(" }");
2151+
f.line(" None");
2152+
f.line(" }");
2153+
f.blank();
2154+
// const-compatible string equality helper.
2155+
f.line(" fn iri_eq(a: &str, b: &str) -> bool {");
2156+
f.line(" a.as_bytes() == b.as_bytes()");
2157+
f.line(" }");
2158+
f.blank();
2159+
f.indented_doc_comment("ADR-057: SDK-facing entry point for shape registration. The");
2160+
f.indented_doc_comment("`register_shape!` SDK macro emits a call to this function at");
2161+
f.indented_doc_comment("crate initialization time. Foundation's MVP registry is");
2162+
f.indented_doc_comment("link-section-collected via the SDK macro; this entry exists for");
2163+
f.indented_doc_comment("future imperative-registration paths (test harnesses, dynamic");
2164+
f.indented_doc_comment("loaders).");
2165+
f.indented_doc_comment("");
2166+
f.indented_doc_comment("Doc-hidden: not part of the application-author surface per ADR-022");
2167+
f.indented_doc_comment("D1's seal-by-naming-convention pattern. The `register_shape!`");
2168+
f.indented_doc_comment("SDK macro is the sanctioned entry point.");
2169+
f.line(" #[doc(hidden)]");
2170+
f.line(" pub fn __register_shape(_shape: &'static RegisteredShape) {");
2171+
f.line(" // MVP: no-op. v0.4.13 ships the registry surface; the");
2172+
f.line(" // link-section-based collection mechanism extends the");
2173+
f.line(" // FOUNDATION_REGISTRY in a follow-up release. Applications");
2174+
f.line(" // requiring registration today consult the wiki ADR-057 for");
2175+
f.line(" // the deferred-to-runtime evaluation discipline.");
2176+
f.line(" }");
2177+
f.line("}");
2178+
f.blank();
20442179
}
20452180

20462181
/// ADR-032 (G5): emits one zero-sized marker type per Witt level, each
@@ -6013,6 +6148,11 @@ fn emit_cartesian_product_shape(f: &mut RustFile) {
60136148
f.line(" conjunct_count,");
60146149
f.line(" }");
60156150
f.line(" }");
6151+
f.line(" // ADR-057: Recurse references a shape by content-addressed IRI;");
6152+
f.line(" // there are no site positions to shift. Pass through unchanged.");
6153+
f.line(" ConstraintRef::Recurse { shape_iri, descent_bound } => {");
6154+
f.line(" ConstraintRef::Recurse { shape_iri, descent_bound }");
6155+
f.line(" }");
60166156
f.line(" }");
60176157
f.line("}");
60186158
f.blank();
@@ -6082,6 +6222,11 @@ fn emit_cartesian_product_shape(f: &mut RustFile) {
60826222
f.line(" bias,");
60836223
f.line(" }");
60846224
f.line(" }");
6225+
f.line(" // ADR-057: Recurse references a shape by content-addressed IRI;");
6226+
f.line(" // there are no site positions to shift. Pass through unchanged.");
6227+
f.line(" LeafConstraintRef::Recurse { shape_iri, descent_bound } => {");
6228+
f.line(" LeafConstraintRef::Recurse { shape_iri, descent_bound }");
6229+
f.line(" }");
60856230
f.line(" }");
60866231
f.line("}");
60876232
f.blank();
@@ -6254,6 +6399,11 @@ fn emit_admission_fns(f: &mut RustFile) {
62546399
f.line(" ConstraintRef::Conjunction { conjuncts, conjunct_count } => {");
62556400
f.line(" conjunction_all_sat(conjuncts, *conjunct_count)");
62566401
f.line(" }");
6402+
f.line(" // ADR-057: const-time validation defers Recurse to runtime");
6403+
f.line(" // admission (parallel to ADR-049's LandauerCost deferral).");
6404+
f.line(" // The only const check is that `shape_iri` is non-empty —");
6405+
f.line(" // the registry lookup happens at the runtime admission path.");
6406+
f.line(" ConstraintRef::Recurse { shape_iri, .. } => !shape_iri.is_empty(),");
62576407
f.line(" };");
62586408
f.line(" if !ok {");
62596409
f.line(" return Err(ShapeViolation {");
@@ -6903,6 +7053,11 @@ fn emit_preflight_checks(f: &mut RustFile, ontology: &Ontology) {
69037053
f.line(
69047054
" ConstraintRef::Conjunction { conjuncts, conjunct_count } => conjunction_all_sat(conjuncts, *conjunct_count),",
69057055
);
7056+
f.line(" // ADR-057: Recurse defers to runtime ψ_1 NerveResolver");
7057+
f.line(" // via the shape-IRI registry. Preflight feasibility");
7058+
f.line(" // accepts on non-empty shape_iri; the registry lookup");
7059+
f.line(" // happens at runtime admission.");
7060+
f.line(" ConstraintRef::Recurse { shape_iri, .. } => !shape_iri.is_empty(),");
69067061
f.line(" };");
69077062
f.line(" if !ok {");
69087063
f.line(" return Err(ShapeViolation {");

0 commit comments

Comments
 (0)