From 1397500479e051657399b1d6620f2b2e73274c4d Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Thu, 15 Oct 2026 23:51:26 +0200 Subject: [PATCH 1/9] research(deepnsm-v2): add Haspelmath continuity to CE64 hydration harness and falsifiers --- crates/deepnsm-v2/src/haspelmath.rs | 394 ++++++++++++++++++++++++++++ 1 file changed, 394 insertions(+) create mode 100644 crates/deepnsm-v2/src/haspelmath.rs diff --git a/crates/deepnsm-v2/src/haspelmath.rs b/crates/deepnsm-v2/src/haspelmath.rs new file mode 100644 index 000000000..668a56fa8 --- /dev/null +++ b/crates/deepnsm-v2/src/haspelmath.rs @@ -0,0 +1,394 @@ +//! Executable Haspelmath semantic-map probe at the DeepNSM-v2 / CE64 / hydration seam. +//! +//! This is a TEST HARNESS, not a universal grammar parser or an ontology mint. +//! Haspelmath (2003), "The Geometry of Grammatical Meaning", pp. 212-219: +//! grammatical functions are cross-linguistically distinguished; the proposed +//! map is a network; attested multi-function distributions are hypothesized to +//! occupy contiguous regions. Spatial positions and line lengths are NOT +//! semantic distances. See .arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md. +//! +//! Critical contract: DeepNSM WordId is u16; CausalEdge64 S/P/O are u8. +//! Never truncate WordId. The CE64 projection below has a reversible, PER VERSE +//! local palette. The high 40 bits remain zero: syntax is not NARS confidence, +//! Pearl causation, evidence independence or epistemic maturity. + +use crate::fsm::{parse_readings, PosSet, Reading}; +use crate::hydrate::{hydrate, Hydration}; +use crate::spo::Spo; +use crate::vocab::{PaletteVocab, WordId}; +use causal_edge::CausalEdge64; +use lance_graph_contract::hhtl::NiblePath; +use std::collections::HashMap; + +/// An explicitly named function from Haspelmath's Fig. 8.1 (p. 213). +/// Ordinals are harness-local mask coordinates, never a CE64 or ISA codebook. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum DativeFunction { + Direction = 0, + Recipient = 1, + Experiencer = 2, + Purpose = 3, + Beneficiary = 4, + PredicativePossessor = 5, + ExternalPossessor = 6, + Judicantis = 7, +} + +impl DativeFunction { + #[must_use] + pub const fn bit(self) -> u8 { + 1 << (self as u8) + } +} + +// Undirected structural links as printed in Fig. 8.1. +// They are hypotheses about neighbors, NOT embedding distances or causal edges. +const NEIGHBORS: [u8; 8] = [ + (1 << 1) | (1 << 3), // direction: recipient, purpose + (1 << 0) | (1 << 2) | (1 << 4) | (1 << 5), + 1 << 1, // experiencer: recipient + 1 << 0, // purpose: direction + (1 << 1) | (1 << 6) | (1 << 7), // beneficiary + (1 << 1) | (1 << 6), // predicative possessor + (1 << 4) | (1 << 5), // external possessor + 1 << 4, // judicantis: beneficiary +]; + +/// Test continuity on the INDUCED graph, not along paths through unlicensed +/// functions. An incomplete sample cannot falsify the universal hypothesis. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum MapVerdict { + Connected, + Disconnected, + Incomplete, +} + +#[must_use] +pub fn continuity(functions: u8, coverage_complete: bool) -> MapVerdict { + if !coverage_complete { + return MapVerdict::Incomplete; + } + if functions == 0 { + return MapVerdict::Disconnected; + } + let mut seen = 1u8 << functions.trailing_zeros(); + loop { + let mut next = seen; + for i in 0..8 { + if seen & (1 << i) != 0 { + next |= NEIGHBORS[i] & functions; + } + } + if next == seen { + break; + } + seen = next; + } + if seen == functions { + MapVerdict::Connected + } else { + MapVerdict::Disconnected + } +} + +/// One independently cited FUNCTION DISTRIBUTION for a grammatical form. +/// This is not a truth value; same evidence_root on two attestations is still +/// one underlying source. "Complete" must be warranted externally. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct FormAttestation { + pub word: WordId, + pub functions: u8, + pub coverage_complete: bool, + pub evidence_root: u64, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum HarnessError { + UnalignedVerses, + UnknownWord, + MissingEvidenceRoot, + DisconnectedCompleteDistribution, + ParserOverflow, + UnaddressedTriples(usize), + LocalPaletteOverflow, +} + +/// Bind surfaces to an existing vocabulary and supplied lexical reading sets. +/// Token segmentation, language-specific PoS decisions and morphology remain +/// upstream responsibilities (COCA/WordNet/UD or the appropriate parser). +pub fn bind_tokens( + vocab: &PaletteVocab, + annotated: &[(&str, PosSet)], +) -> Result, HarnessError> { + annotated + .iter() + .map(|(surface, pos)| { + vocab + .id(&surface.to_lowercase()) + .map(|id| Reading::new(id, *pos)) + .ok_or(HarnessError::UnknownWord) + }) + .collect() +} + +/// CE64's grammar-only payload has no truth/causality/witness claims. +/// The three indices refer to the per-path palette in HarnessOutput. +#[derive(Clone, Copy)] +pub struct AddressedSyntax { + pub path: NiblePath, + pub order: u32, + pub word: CausalEdge64, +} + +pub struct HarnessOutput { + pub hydration: Hydration, + pub encoded: Vec, + pub local_palettes: HashMap>, + /// Uncertain triples stay associated with their exact input verse ordinal. + /// They are NEVER passed as certain givens to hydrate(). + pub alternatives: Vec<(usize, Spo)>, + pub attestations: Vec<(usize, FormAttestation, MapVerdict)>, + pub ambiguous_tokens: usize, +} + +impl HarnessOutput { + /// Reconstruct u16 global vocabulary identity, using the SAME path as the + /// edge. Treating CE64 low bytes as global WordIds would be lossy. + #[must_use] + pub fn decode(&self, edge: &AddressedSyntax) -> Option { + let palette = self.local_palettes.get(&edge.path)?; + Some(Spo::new( + *palette.get(edge.word.s_idx() as usize)?, + *palette.get(edge.word.p_idx() as usize)?, + *palette.get(edge.word.o_idx() as usize)?, + )) + } +} + +/// Encode already-hydrated CERTAIN triples, with one reversible local u8 +/// codebook per verse address. This is deliberately a reference implementation, +/// not a throughput claim: each lookup scans at most 256 entries. +/// An actual writer must persist the palette with its sealed-version identity. +fn encode_hydration( + hydration: &Hydration, +) -> Result<(Vec, HashMap>), HarnessError> { + let mut palettes: HashMap> = HashMap::new(); + let mut encoded = Vec::with_capacity(hydration.triples.len()); + for triple in &hydration.triples { + let palette = palettes.entry(triple.path).or_default(); + let mut idx = [0u8; 3]; + for (i, id) in [ + triple.spo.subject, + triple.spo.predicate, + triple.spo.object, + ] + .into_iter() + .enumerate() + { + let index = if let Some(existing) = palette.iter().position(|&x| x == id) { + existing + } else { + if palette.len() == 256 { + return Err(HarnessError::LocalPaletteOverflow); + } + palette.push(id); + palette.len() - 1 + }; + idx[i] = index as u8; + } + let mut word = CausalEdge64::ZERO; + word.set_s_idx(idx[0]); + word.set_p_idx(idx[1]); + word.set_o_idx(idx[2]); + encoded.push(AddressedSyntax { + path: triple.path, + order: triple.order, + word, + }); + } + Ok((encoded, palettes)) +} + +/// Executable seam: known/readable tokens -> existing multi-reading FSM -> +/// CERTAIN SPO -> existing hydrate.rs -> reversible syntax-only CE64 view. +/// +/// The semantic map checks ATTESTED form distributions, not token-level word +/// similarity. Neither a connected map nor a grammatical fit proves a causal +/// or NARS inference. Refuses mismatched verse walks and address loss. +pub fn run_harness( + markers: &[(u16, u16)], + verses: &[Vec], + form_evidence: &[Vec], + basin: u8, +) -> Result { + if markers.len() != verses.len() || markers.len() != form_evidence.len() { + return Err(HarnessError::UnalignedVerses); + } + let mut attestations = Vec::new(); + for (verse, forms) in form_evidence.iter().enumerate() { + for &record in forms { + if record.evidence_root == 0 { + return Err(HarnessError::MissingEvidenceRoot); + } + let verdict = continuity(record.functions, record.coverage_complete); + if verdict == MapVerdict::Disconnected { + return Err(HarnessError::DisconnectedCompleteDistribution); + } + attestations.push((verse, record, verdict)); + } + } + let mut certain = Vec::with_capacity(verses.len()); + let mut alternatives = Vec::new(); + let mut ambiguous_tokens = 0; + for (verse, tokens) in verses.iter().enumerate() { + let mut input = tokens.clone(); + input.push(Reading::stop()); + let parsed = parse_readings(&input); + if parsed.overflow_flushes != 0 { + return Err(HarnessError::ParserOverflow); + } + ambiguous_tokens += parsed.ambiguous.len(); + alternatives.extend(parsed.alternative.into_iter().map(|spo| (verse, spo))); + certain.push(parsed.certain); + } + let hydration = hydrate(markers, &certain, basin); + if hydration.unaddressed != 0 { + return Err(HarnessError::UnaddressedTriples(hydration.unaddressed)); + } + let (encoded, local_palettes) = encode_hydration(&hydration)?; + Ok(HarnessOutput { + hydration, + encoded, + local_palettes, + alternatives, + attestations, + ambiguous_tokens, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::fsm::Pos; + + fn one(id: WordId, pos: Pos) -> Reading { + Reading::new(id, PosSet::single(pos)) + } + + #[test] + fn haspelmath_to_and_zu_are_connected_but_unrelated_pair_is_not() { + use DativeFunction as F; + let english_to = F::Direction.bit() + | F::Recipient.bit() + | F::Purpose.bit() + | F::Experiencer.bit(); + assert_eq!(continuity(english_to, true), MapVerdict::Connected); + assert_eq!( + continuity(F::Direction.bit() | F::Purpose.bit(), true), + MapVerdict::Connected + ); + assert_eq!( + continuity(F::Purpose.bit() | F::Judicantis.bit(), true), + MapVerdict::Disconnected + ); + assert_eq!( + continuity(F::Purpose.bit() | F::Judicantis.bit(), false), + MapVerdict::Incomplete + ); + } + + #[test] + fn real_fsm_then_hydrate_then_ce64_roundtrips_global_ids() { + let forms = vec![vec![FormAttestation { + word: 42, + functions: DativeFunction::Direction.bit() | DativeFunction::Purpose.bit(), + coverage_complete: true, + evidence_root: 0xABC, + }]]; + let v = vec![vec![ + one(0x0101, Pos::Noun), + one(0x1234, Pos::Verb), + one(0xFFFF, Pos::Noun), + ]]; + let output = run_harness(&[(1, 1)], &v, &forms, 3).unwrap(); + assert_eq!(output.hydration.unaddressed, 0); + assert_eq!(output.encoded.len(), 1); + assert_eq!(output.hydration.triples.len(), 1); + let e = &output.encoded[0]; + assert_eq!(output.decode(e), Some(Spo::new(0x0101, 0x1234, 0xFFFF))); + assert_eq!(e.order, output.hydration.triples[0].order); + assert_eq!(e.path, output.hydration.triples[0].path); + assert_eq!(e.word.0 >> 24, 0, "no fabricated truth, Pearl or maturity"); + } + + #[test] + fn incomplete_map_can_be_stored_as_unresolved_evidence() { + let att = FormAttestation { + word: 7, + functions: DativeFunction::Purpose.bit() | DativeFunction::Judicantis.bit(), + coverage_complete: false, + evidence_root: 1, + }; + let r = run_harness(&[(1, 1)], &[vec![]], &[vec![att]], 1).unwrap(); + assert_eq!(r.attestations[0].2, MapVerdict::Incomplete); + assert!(r.encoded.is_empty()); + assert_eq!(r.hydration.verse_nodes(), 1); + assert_eq!( + run_harness( + &[(1, 1)], + &[vec![]], + &[vec![FormAttestation { coverage_complete: true, ..att }]], + 1, + ).err(), + Some(HarnessError::DisconnectedCompleteDistribution) + ); + } + + #[test] + fn ambiguity_is_retained_not_minted_as_a_given() { + let tokens = vec![ + one(9, Pos::Det), + one(1, Pos::Noun), + Reading::new(2, PosSet::single(Pos::Noun).with(Pos::Verb)), + one(3, Pos::Noun), + ]; + let mut with_stop = tokens.clone(); + with_stop.push(Reading::stop()); + let oracle = parse_readings(&with_stop); + let r = run_harness(&[(1, 1)], &[tokens], &[vec![]], 2).unwrap(); + assert_eq!(r.ambiguous_tokens, oracle.ambiguous.len()); + assert_eq!(r.alternatives, oracle.alternative.into_iter().map(|s| (0, s)).collect::>()); + assert_eq!(r.hydration.triples.iter().map(|t| t.spo).collect::>(), oracle.certain); + } + + #[test] + fn local_palette_refuses_overflow_instead_of_truncating() { + let triples: Vec = (0..86u16) + .map(|i| Spo::new(i * 3, i * 3 + 1, i * 3 + 2)) + .collect(); + let h = hydrate(&[(1, 1)], &[triples], 1); + assert_eq!( + encode_hydration(&h).err(), + Some(HarnessError::LocalPaletteOverflow) + ); + } + + #[test] + fn refuses_unaligned_walk_and_missing_evidence_provenance() { + assert_eq!( + run_harness(&[(1, 1)], &[], &[], 1).err(), + Some(HarnessError::UnalignedVerses) + ); + let forms = vec![vec![FormAttestation { + word: 1, + functions: DativeFunction::Recipient.bit(), + coverage_complete: true, + evidence_root: 0, + }]]; + assert_eq!( + run_harness(&[(1, 1)], &[vec![]], &forms, 1).err(), + Some(HarnessError::MissingEvidenceRoot) + ); + } +} From b332043175ccbedda9e9e42a72f250e57e5cc6d9 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Thu, 15 Oct 2026 23:51:49 +0200 Subject: [PATCH 2/9] feat(deepnsm-v2): expose additive Haspelmath research harness --- crates/deepnsm-v2/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/deepnsm-v2/src/lib.rs b/crates/deepnsm-v2/src/lib.rs index 7615414df..b0de36863 100644 --- a/crates/deepnsm-v2/src/lib.rs +++ b/crates/deepnsm-v2/src/lib.rs @@ -42,6 +42,7 @@ pub mod codebook; pub mod corpus; pub mod evidence; pub mod fsm; +pub mod haspelmath; pub mod hydrate; pub mod introspect; pub mod lexical; From 98c9945f2a4e7ac04c8b095f635c6d73100c4bda Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Thu, 15 Oct 2026 23:53:18 +0200 Subject: [PATCH 3/9] docs: source-grounded Haspelmath contract, falsifiers and research follow-ons --- ...2026-10_haspelmath-deepnsm-ce64-harness.md | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 .arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md diff --git a/.arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md b/.arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md new file mode 100644 index 000000000..6e307f19d --- /dev/null +++ b/.arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md @@ -0,0 +1,150 @@ +# Haspelmath semantic-map → DeepNSM-v2 → CE64 → hydrate.rs +**Research/executable harness · 15 October 2026 · not a production writer** + +## Thesis + +The substrate already has stable word identities, a multi-reading grammatical FSM, and +verse addressing. Use Martin **Haspelmath** (not "Haspelmann") as a falsifiable +**linguistic-function continuity constraint**, not as a new grammar parser, a semantic +distance function, or an instruction set. The resulting pipeline is: + +``` +existing lexical source (COCA / UD / WordNet / language-aware morphology) + -> bind_tokens: (surface, PosSet) -> Reading (u16 WordId; OOV refused) + -> parse_readings: certain / alternative / ambiguity / overflow + -> [separate attested grammatical-form function masks] + -> hydrate(markers, per_verse_certain, basin): SPO + original verse path + order + -> CausalEdge64 syntactic view (S/P/O local u8 indices) + + sealed-version-scoped per-verse reversible u8 <-> u16 codebook + -> downstream authority/provenance/temporal writer: NOT IMPLEMENTED +``` + +This executable probe is in `crates/deepnsm-v2/src/haspelmath.rs`. +It changes no existing grammar decision, hydration behavior, CE64 bit definition, +or Lance/OGAR writer. + +## Primary source, not paraphrased into a stronger claim + +Martin Haspelmath, *The Geometry of Grammatical Meaning: Semantic Maps +and Cross-Linguistic Comparison*, chapter 8 in *The New Psychology of Language, +Volume 2* (2003), user-provided scan `SemMaps.pdf`, printed pp. 211–242. + +- **pp. 212–213 and Fig. 8.1**: "functions" is deliberately neutral between + different senses and context-dependent uses. English *to* spans direction, + recipient, experiencer, and purpose. The other dative functions in Fig. 8.1 + are not necessarily uses of English *to*. +- **p. 216, Fig. 8.3**: an edge indicates adjacency. Its drawing orientation + and physical length have no linguistic significance. Do NOT use Euclidean, + Morton or word-ID distance as proof of semantic proximity. +- **pp. 216–217**: candidate maps are induced from contrasts between + languages. A multifunctional gram is **hypothesized** to occupy a contiguous + region. The arrangement is not mechanically uniquely determined by one + language; independent cross-linguistic observations constrain it. +- **pp. 222–223, Figs. 8.6–8.8**: indefinite-pronoun distributions are a second + family of semantic functions, not free additional dative nodes. Different + languages carve distinct connected subsets. +- **pp. 230–231**: linking neighboring maps into a larger map is possible, but + the useful extent of any map depends on the question; the method does not + require deciding whether each polyfunction is polysemy or vagueness. + +**Interpretation discipline:** a disconnected, genuinely *complete* attested +function set falsifies this particular proposed map. A disconnected *partial* +sample is unresolved, not a grammar error. A connected set is compatible with +the proposed map, not proof of meaning, truth, or actual referential correctness. + +The example graph is exactly the **eight Fig. 8.1 dative-function nodes**, +with the illustrated undirected connections. Its bit positions are strictly +local to this research example, not new classid, CE64 or ABI assignments. + +## What is proven by code vs still missing + +| Existing code, consumed | Harness addition | Still outside scope | +|---|---|---| +| `fsm::Reading / PosSet / parse_readings` | Existing lexical alternatives remain alternatives | German case, full morphological agreement, nested relatives | +| `spo::Spo` with **u16** IDs | Per-verse reversible remap for **u8 CE64 slots** | Globally stable CE64 vocabulary encoding | +| `hydrate::hydrate` | Counts/addresses verified; unaddressed triples refused | Index-only hydration replacing the TOC, full throughput claim | +| `CausalEdge64::ZERO` and S/P/O setters | Grammar-only low 24 bits, *high 40 zero* | Evidence/root persistence and NAL confidence calibration | +| `tekamolo::read_clause`, `loci`, `wave` | Explicit future join points | TEKAMOLO x Haspelmath adjudication and 24xi4 anaphora | +| H12 (#1551) semantic-map preregistration | Executable linguistic falsifier, not H12 replacement | Inference-function cross-system H12 comparisons | + +**Do not conflate:** +1. English *to* vs French *à* is a comparison of multifunctionality, + not a mathematical mapping from the lexical word "to" to its WordId neighbors. +2. The lower 24 bits of a CE64 register have three **u8 local** codes here, + not the `u16` `Spo::pack` layout. The sidecar is indispensable and must + be persisted atomically by any future production writer. +3. Syntax does not deserve f=1, c=1, a Pearl intervention mark, or + `EpistemicState5::Causes`. Bare grammar output has no independent + witness-based evidence roots. This probe leaves the CE64 header unset. +4. `form_evidence.evidence_root` is an external provenance identifier to + track, not an independent observation count; never revise confidence twice + just because two thought layers reference the same root. +5. `hydrate.rs` addresses the already parsed triple stream through a TOC. + It does not derive SPO triples or parse morphology. + +## Reproducible tests / falsifiers + +```bash +cargo test --manifest-path crates/deepnsm-v2/Cargo.toml haspelmath +cargo test --manifest-path crates/deepnsm-v2/Cargo.toml --all-targets +cargo clippy --manifest-path crates/deepnsm-v2/Cargo.toml --all-targets -- -D warnings +cargo fmt --manifest-path crates/deepnsm-v2/Cargo.toml --check +``` + +| Gate | Test | Kills | +|---|---|---| +| HSM-0 | Fig. 8.1 English *to*, German *zu*: connected | Wrong adjacency topology | +| HSM-1 | Purpose+judicantis: disjoint | A vacuous "everything is adjacent" map | +| HSM-2 | Incomplete function evidence stays `Incomplete` | Mistaking missing linguistic data for contradiction | +| HSM-3 | Single verse FSM → hydrate → CE64 → u16 roundtrip (IDs >255) | Silent `u16 as u8` truncation | +| HSM-4 | Parser alternatives preserved separately from certain hydrated givens | Silent arbitrary disambiguation | +| HSM-5 | One verse, 258 different IDs | Silent codebook overflow/aliasing | +| HSM-6 | Mismatched per-verse markers refused | Cross-verse identity drift | +| HSM-7 | Missing evidence source refused | Unsupported evidence annotation | +| HSM-8 | CE64 upper bits remain zero | Fabricated NARS/Pearl/epistemic certainty | + +The code tests are *authored*, not reported as locally run. CI/local Cargo +verification is required before enabling consumers or calling the gates green. + +## Next rung (separate approved PRs) + +**Wave A: Annotated token-to-function admission.** Read UD case/morphology, +function evidence and cross-language correspondences as externally identified +witnesses. Compare English *to*, German *zu*, French *à* on Haspelmath's +recorded examples. The grammar parser must not treat these as universal +decision rules. Study a counterexample and require a FAIL/REVISION path. + +**Wave B: Grammatical Sudoku.** Cross-join the admissible function mask with +SPO/TEKAMOLO, relative-clause argument roles, and 24xi4 local antecedent +displacements as *separate typed readings* of the immutable ABI. +Preserve multiplicity, lexical unknowns, scope, ambiguity and signed local +pointer overflow. Unbound references escalate instead of being guessed. + +**Wave C: Hydrated CE64 evidence.** Add a genuinely authorized writer whose +sidecar scope is `(classid, sealed version, verse path)`, preserving +stable word IDs, grammar receipts, original evidence roots, source timestamps, +and read authorization. Require CE64 high-bit interpretations to follow the +current global header contract; no private reassignments. + +**Wave D: Measurement.** Pin the KJV + Luther corpus snapshots, report +tokenization/PoS/grammar/hydration/CE64 packing separately, with cold/warm +batches, peak allocation and accuracy against held-out UD gold. A 64K +addressable corpus and fast hydration are *not* proof that grammar or +counterfactual inference was solved in the same time. Compare exact candidate +sets to the existing parser oracle before claiming a speedup. + +## Kill / stop conditions + +- A complete cross-linguistic attestation disconnected on a frozen map: + **map falsified**, not an invitation to modify oracle data to fit. +- Broken u16 recovery or local palette overflow: **refuse CE64 projection**. +- Any altered `parse_readings` certain/alternative accounting: **STOP**. +- Inference from grammatical contiguity to causality or truth confidence: + **STOP**. +- Source-root duplication elevating confidence, stale temporal windows, or + unauthorized view composition: **STOP**. +- A build lacking the relevant production writer: **do not call it wired**. + +Related plans: D-HOLO-H12 in #1551, D-ORACLE-0 in #1549, +D-HL-5 in #1564, D-MTP-0 in #1555, the DeepNSM-v2 D-LXC experiments +in #1321, and the source-of-truth register/semantic distinction. From 34d043503966191abdac574929794bc515259634 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Thu, 15 Oct 2026 23:53:52 +0200 Subject: [PATCH 4/9] examples: run token bindings through semantic-map guard, hydrate and CE64 roundtrip --- .../deepnsm-v2/examples/haspelmath_wiring.rs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 crates/deepnsm-v2/examples/haspelmath_wiring.rs diff --git a/crates/deepnsm-v2/examples/haspelmath_wiring.rs b/crates/deepnsm-v2/examples/haspelmath_wiring.rs new file mode 100644 index 000000000..8fb67104b --- /dev/null +++ b/crates/deepnsm-v2/examples/haspelmath_wiring.rs @@ -0,0 +1,57 @@ +//! Small deterministic CLI fixture for the Haspelmath wiring seam. +//! Run: cargo run --manifest-path crates/deepnsm-v2/Cargo.toml --example haspelmath_wiring +//! The witness and grammatical-function assignment are TEST INPUTS, not mined +//! evidence, and no CE64 truth/causal headers are minted by this example. + +use deepnsm_v2::fsm::{Pos, PosSet}; +use deepnsm_v2::haspelmath::{ + bind_tokens, run_harness, DativeFunction, FormAttestation, +}; +use deepnsm_v2::vocab::PaletteVocab; + +fn main() { + let mut vocab = PaletteVocab::new(); + vocab.from_frequency_ranked(["doctor", "gave", "letter", "to"]); + let p = |pos| PosSet::single(pos); + let tokens = bind_tokens( + &vocab, + &[ + ("doctor", p(Pos::Noun)), + ("gave", p(Pos::Verb)), + ("letter", p(Pos::Noun)), + ("to", p(Pos::Other)), + ], + ) + .expect("known words"); + + // English 'to' covers this four-function region in Fig. 8.1. + // "coverage_complete" is a controlled fixture assumption, not + // automatically inferred by observing one token occurrence. + let attestation = FormAttestation { + word: vocab.id("to").expect("known"), + functions: DativeFunction::Direction.bit() + | DativeFunction::Recipient.bit() + | DativeFunction::Purpose.bit() + | DativeFunction::Experiencer.bit(), + coverage_complete: true, + evidence_root: 1, + }; + let out = run_harness(&[(1, 1)], &[tokens], &[vec![attestation]], 3) + .expect("fixture is addressable"); + for edge in &out.encoded { + let decoded = out.decode(edge).expect("reversible local palette"); + println!( + "verse={:?} order={} SPO=({}, {}, {}) ce64={:016x} map={:?}", + edge.path, + edge.order, + vocab.word(decoded.subject).unwrap_or("OOV"), + vocab.word(decoded.predicate).unwrap_or("OOV"), + vocab.word(decoded.object).unwrap_or("OOV"), + edge.word.0, + out.attestations[0].2 + ); + } + assert_eq!(out.encoded.len(), 1); + assert_eq!(out.hydration.unaddressed, 0); + assert_eq!(out.encoded[0].word.0 >> 24, 0); +} From 97f8f54fe1cff58d478afe935158333bc04d7c47 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 16 Oct 2026 00:02:16 +0200 Subject: [PATCH 5/9] fix(deepnsm-v2): freeze epoch-wide thought operand ABI; forbid per-verse CE64 remapping --- crates/deepnsm-v2/src/haspelmath.rs | 165 ++++++++++++++++++---------- 1 file changed, 107 insertions(+), 58 deletions(-) diff --git a/crates/deepnsm-v2/src/haspelmath.rs b/crates/deepnsm-v2/src/haspelmath.rs index 668a56fa8..86da2b6ae 100644 --- a/crates/deepnsm-v2/src/haspelmath.rs +++ b/crates/deepnsm-v2/src/haspelmath.rs @@ -111,7 +111,10 @@ pub enum HarnessError { DisconnectedCompleteDistribution, ParserOverflow, UnaddressedTriples(usize), - LocalPaletteOverflow, + AbiPaletteOverflow, + InvalidAbiVersion, + DuplicateCanonicalOperand(WordId), + UnknownCanonicalOperand(WordId), } /// Bind surfaces to an existing vocabulary and supplied lexical reading sets. @@ -132,19 +135,65 @@ pub fn bind_tokens( .collect() } +/// A FROZEN, VERSION-IDENTIFIED register operand dictionary, provided by +/// the consumer's shared ABI/codebook registry. The harness may NOT invent +/// one per verse, per query, per thought or per grammatical interpretation. +/// +/// Canonical agreement is an external deployment requirement; version equality +/// only detects mismatches, it does not prove independent implementations chose +/// the same contents. This small dictionary is an explicit probe limitation: +/// a real global 65K lexical corpus cannot be squeezed into 256 operand codes +/// without wider addressing/indirection defined by the canonical ISA. +#[derive(Clone, Debug)] +pub struct FrozenOperandAbi { + pub version: u64, + operands: Vec, + by_word: HashMap, +} + +impl FrozenOperandAbi { + pub fn new(version: u64, operands: &[WordId]) -> Result { + if version == 0 { + return Err(HarnessError::InvalidAbiVersion); + } + if operands.len() > 256 { + return Err(HarnessError::AbiPaletteOverflow); + } + let mut by_word = HashMap::new(); + for (i, &word) in operands.iter().enumerate() { + if by_word.insert(word, i as u8).is_some() { + return Err(HarnessError::DuplicateCanonicalOperand(word)); + } + } + Ok(Self { version, operands: operands.to_vec(), by_word }) + } + + fn code(&self, word: WordId) -> Result { + self.by_word + .get(&word) + .copied() + .ok_or(HarnessError::UnknownCanonicalOperand(word)) + } + + fn word(&self, code: u8) -> Option { + self.operands.get(code as usize).copied() + } +} + /// CE64's grammar-only payload has no truth/causality/witness claims. -/// The three indices refer to the per-path palette in HarnessOutput. +/// The three u8 operand codes are interpreted by ONE externally pinned +/// register dictionary for the entire epoch, not a per-verse palette. #[derive(Clone, Copy)] pub struct AddressedSyntax { pub path: NiblePath, pub order: u32, + pub abi_version: u64, pub word: CausalEdge64, } pub struct HarnessOutput { pub hydration: Hydration, pub encoded: Vec, - pub local_palettes: HashMap>, /// Uncertain triples stay associated with their exact input verse ordinal. /// They are NEVER passed as certain givens to hydrate(). pub alternatives: Vec<(usize, Spo)>, @@ -153,61 +202,43 @@ pub struct HarnessOutput { } impl HarnessOutput { - /// Reconstruct u16 global vocabulary identity, using the SAME path as the - /// edge. Treating CE64 low bytes as global WordIds would be lossy. + /// Interpret register operands ONLY under the matching canonical + /// version. Cross-version decoding is a refusal, not best-effort guessing. #[must_use] - pub fn decode(&self, edge: &AddressedSyntax) -> Option { - let palette = self.local_palettes.get(&edge.path)?; + pub fn decode(&self, edge: &AddressedSyntax, abi: &FrozenOperandAbi) -> Option { + if edge.abi_version != abi.version { + return None; + } Some(Spo::new( - *palette.get(edge.word.s_idx() as usize)?, - *palette.get(edge.word.p_idx() as usize)?, - *palette.get(edge.word.o_idx() as usize)?, + abi.word(edge.word.s_idx())?, + abi.word(edge.word.p_idx())?, + abi.word(edge.word.o_idx())?, )) } } -/// Encode already-hydrated CERTAIN triples, with one reversible local u8 -/// codebook per verse address. This is deliberately a reference implementation, -/// not a throughput claim: each lookup scans at most 256 entries. -/// An actual writer must persist the palette with its sealed-version identity. +/// Encode already-hydrated CERTAIN triples using a shared frozen operand +/// vocabulary. No ephemeral remapping and no silent truncation. This is still +/// only an adapter experiment; production must supply a true canonical global +/// registry and stable cross-class/temporal addressing. fn encode_hydration( hydration: &Hydration, -) -> Result<(Vec, HashMap>), HarnessError> { - let mut palettes: HashMap> = HashMap::new(); + abi: &FrozenOperandAbi, +) -> Result, HarnessError> { let mut encoded = Vec::with_capacity(hydration.triples.len()); for triple in &hydration.triples { - let palette = palettes.entry(triple.path).or_default(); - let mut idx = [0u8; 3]; - for (i, id) in [ - triple.spo.subject, - triple.spo.predicate, - triple.spo.object, - ] - .into_iter() - .enumerate() - { - let index = if let Some(existing) = palette.iter().position(|&x| x == id) { - existing - } else { - if palette.len() == 256 { - return Err(HarnessError::LocalPaletteOverflow); - } - palette.push(id); - palette.len() - 1 - }; - idx[i] = index as u8; - } let mut word = CausalEdge64::ZERO; - word.set_s_idx(idx[0]); - word.set_p_idx(idx[1]); - word.set_o_idx(idx[2]); + word.set_s_idx(abi.code(triple.spo.subject)?); + word.set_p_idx(abi.code(triple.spo.predicate)?); + word.set_o_idx(abi.code(triple.spo.object)?); encoded.push(AddressedSyntax { path: triple.path, order: triple.order, + abi_version: abi.version, word, }); } - Ok((encoded, palettes)) + Ok(encoded) } /// Executable seam: known/readable tokens -> existing multi-reading FSM -> @@ -221,6 +252,7 @@ pub fn run_harness( verses: &[Vec], form_evidence: &[Vec], basin: u8, + abi: &FrozenOperandAbi, ) -> Result { if markers.len() != verses.len() || markers.len() != form_evidence.len() { return Err(HarnessError::UnalignedVerses); @@ -256,11 +288,10 @@ pub fn run_harness( if hydration.unaddressed != 0 { return Err(HarnessError::UnaddressedTriples(hydration.unaddressed)); } - let (encoded, local_palettes) = encode_hydration(&hydration)?; + let encoded = encode_hydration(&hydration, abi)?; Ok(HarnessOutput { hydration, encoded, - local_palettes, alternatives, attestations, ambiguous_tokens, @@ -311,12 +342,15 @@ mod tests { one(0x1234, Pos::Verb), one(0xFFFF, Pos::Noun), ]]; - let output = run_harness(&[(1, 1)], &v, &forms, 3).unwrap(); + let abi = FrozenOperandAbi::new(7, &[0x0101, 0x1234, 0xFFFF]).unwrap(); + let output = run_harness(&[(1, 1)], &v, &forms, 3, &abi).unwrap(); assert_eq!(output.hydration.unaddressed, 0); assert_eq!(output.encoded.len(), 1); assert_eq!(output.hydration.triples.len(), 1); let e = &output.encoded[0]; - assert_eq!(output.decode(e), Some(Spo::new(0x0101, 0x1234, 0xFFFF))); + assert_eq!(output.decode(e, &abi), Some(Spo::new(0x0101, 0x1234, 0xFFFF))); + let other_version = FrozenOperandAbi::new(8, &[0x0101, 0x1234, 0xFFFF]).unwrap(); + assert_eq!(output.decode(e, &other_version), None); assert_eq!(e.order, output.hydration.triples[0].order); assert_eq!(e.path, output.hydration.triples[0].path); assert_eq!(e.word.0 >> 24, 0, "no fabricated truth, Pearl or maturity"); @@ -330,7 +364,8 @@ mod tests { coverage_complete: false, evidence_root: 1, }; - let r = run_harness(&[(1, 1)], &[vec![]], &[vec![att]], 1).unwrap(); + let abi = FrozenOperandAbi::new(1, &[]).unwrap(); + let r = run_harness(&[(1, 1)], &[vec![]], &[vec![att]], 1, &abi).unwrap(); assert_eq!(r.attestations[0].2, MapVerdict::Incomplete); assert!(r.encoded.is_empty()); assert_eq!(r.hydration.verse_nodes(), 1); @@ -340,6 +375,7 @@ mod tests { &[vec![]], &[vec![FormAttestation { coverage_complete: true, ..att }]], 1, + &abi, ).err(), Some(HarnessError::DisconnectedCompleteDistribution) ); @@ -356,28 +392,41 @@ mod tests { let mut with_stop = tokens.clone(); with_stop.push(Reading::stop()); let oracle = parse_readings(&with_stop); - let r = run_harness(&[(1, 1)], &[tokens], &[vec![]], 2).unwrap(); + let abi = FrozenOperandAbi::new(1, &[1, 2, 3, 9]).unwrap(); + let r = run_harness(&[(1, 1)], &[tokens], &[vec![]], 2, &abi).unwrap(); assert_eq!(r.ambiguous_tokens, oracle.ambiguous.len()); assert_eq!(r.alternatives, oracle.alternative.into_iter().map(|s| (0, s)).collect::>()); assert_eq!(r.hydration.triples.iter().map(|t| t.spo).collect::>(), oracle.certain); } #[test] - fn local_palette_refuses_overflow_instead_of_truncating() { - let triples: Vec = (0..86u16) - .map(|i| Spo::new(i * 3, i * 3 + 1, i * 3 + 2)) - .collect(); - let h = hydrate(&[(1, 1)], &[triples], 1); - assert_eq!( - encode_hydration(&h).err(), - Some(HarnessError::LocalPaletteOverflow) - ); + fn fixed_operand_abi_refuses_overflow_and_unknown_ids() { + let words: Vec = (0..=256).collect(); + assert!(matches!( + FrozenOperandAbi::new(1, &words), + Err(HarnessError::AbiPaletteOverflow) + )); + let abi = FrozenOperandAbi::new(1, &(0..256).collect::>()).unwrap(); + let h = hydrate(&[(1, 1)], &[vec![Spo::new(10, 20, 256)]], 1); + assert!(matches!( + encode_hydration(&h, &abi), + Err(HarnessError::UnknownCanonicalOperand(256)) + )); + assert!(matches!( + FrozenOperandAbi::new(0, &[1]), + Err(HarnessError::InvalidAbiVersion) + )); + assert!(matches!( + FrozenOperandAbi::new(1, &[1, 1]), + Err(HarnessError::DuplicateCanonicalOperand(1)) + )); } #[test] fn refuses_unaligned_walk_and_missing_evidence_provenance() { + let abi = FrozenOperandAbi::new(1, &[]).unwrap(); assert_eq!( - run_harness(&[(1, 1)], &[], &[], 1).err(), + run_harness(&[(1, 1)], &[], &[], 1, &abi).err(), Some(HarnessError::UnalignedVerses) ); let forms = vec![vec![FormAttestation { @@ -387,7 +436,7 @@ mod tests { evidence_root: 0, }]]; assert_eq!( - run_harness(&[(1, 1)], &[vec![]], &forms, 1).err(), + run_harness(&[(1, 1)], &[vec![]], &forms, 1, &abi).err(), Some(HarnessError::MissingEvidenceRoot) ); } From e6458a121db94bd5c7ef90680e6c5f0442d91701 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 16 Oct 2026 00:02:29 +0200 Subject: [PATCH 6/9] examples: decode CE64 through one frozen versioned thought operand contract --- crates/deepnsm-v2/examples/haspelmath_wiring.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/deepnsm-v2/examples/haspelmath_wiring.rs b/crates/deepnsm-v2/examples/haspelmath_wiring.rs index 8fb67104b..b66d18f24 100644 --- a/crates/deepnsm-v2/examples/haspelmath_wiring.rs +++ b/crates/deepnsm-v2/examples/haspelmath_wiring.rs @@ -5,7 +5,7 @@ use deepnsm_v2::fsm::{Pos, PosSet}; use deepnsm_v2::haspelmath::{ - bind_tokens, run_harness, DativeFunction, FormAttestation, + bind_tokens, run_harness, DativeFunction, FormAttestation, FrozenOperandAbi, }; use deepnsm_v2::vocab::PaletteVocab; @@ -36,10 +36,19 @@ fn main() { coverage_complete: true, evidence_root: 1, }; - let out = run_harness(&[(1, 1)], &[tokens], &[vec![attestation]], 3) + // Register ABI is version-pinned across the entire execution epoch. + // This tiny shared dictionary is a fixture, not the deployed global ISA. + let abi = FrozenOperandAbi::new(1, &[ + vocab.id("doctor").unwrap(), + vocab.id("gave").unwrap(), + vocab.id("letter").unwrap(), + vocab.id("to").unwrap(), + ]) + .expect("shared dictionary fixture"); + let out = run_harness(&[(1, 1)], &[tokens], &[vec![attestation]], 3, &abi) .expect("fixture is addressable"); for edge in &out.encoded { - let decoded = out.decode(edge).expect("reversible local palette"); + let decoded = out.decode(edge, &abi).expect("frozen ABI decoding"); println!( "verse={:?} order={} SPO=({}, {}, {}) ce64={:016x} map={:?}", edge.path, From 2a6a713d90af69ee6f5c5498a25edf977c43a026 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 16 Oct 2026 00:03:14 +0200 Subject: [PATCH 7/9] docs: correct CE64 8:8:8 as frozen ALU/ISA contract, not per-verse dictionary --- ...2026-10_haspelmath-deepnsm-ce64-harness.md | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/.arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md b/.arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md index 6e307f19d..fa6056535 100644 --- a/.arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md +++ b/.arxiv/2026-10_haspelmath-deepnsm-ce64-harness.md @@ -14,12 +14,23 @@ existing lexical source (COCA / UD / WordNet / language-aware morphology) -> parse_readings: certain / alternative / ambiguity / overflow -> [separate attested grammatical-form function masks] -> hydrate(markers, per_verse_certain, basin): SPO + original verse path + order - -> CausalEdge64 syntactic view (S/P/O local u8 indices) - + sealed-version-scoped per-verse reversible u8 <-> u16 codebook + -> CausalEdge64 syntactic operand view (8:8:8 fixed register/ISA contract) + + ONE externally pinned, immutable epoch-wide operand dictionary + + version-qualified canonical meaning for all readers -> downstream authority/provenance/temporal writer: NOT IMPLEMENTED ``` This executable probe is in `crates/deepnsm-v2/src/haspelmath.rs`. + +**ABI correction (15 Oct):** The original draft mistakenly introduced a +per-verse palette. That would make the same CE64 operand byte mean different +things in two verses, defeating the intention of a globally interoperable +8:8:8 register contract. The implementation now requires a single frozen, +explicit, version-identified operand dictionary for the execution epoch. +This is a test fixture only until the canonical ISA/codebook registry supplies +and verifies that dictionary across independent clients. BF16 and TCP/IP are +*interoperability analogies*, not claims that a numerical format alone grounds +semantic truth or that every NAL/Hyperon operator is equivalent. It changes no existing grammar decision, hydration behavior, CE64 bit definition, or Lance/OGAR writer. @@ -61,7 +72,7 @@ local to this research example, not new classid, CE64 or ABI assignments. | Existing code, consumed | Harness addition | Still outside scope | |---|---|---| | `fsm::Reading / PosSet / parse_readings` | Existing lexical alternatives remain alternatives | German case, full morphological agreement, nested relatives | -| `spo::Spo` with **u16** IDs | Per-verse reversible remap for **u8 CE64 slots** | Globally stable CE64 vocabulary encoding | +| `spo::Spo` with **u16** IDs | Fixed epoch-wide dictionary (max 256 operands) for CE64's **u8** slots | Production canonical registry, full-vocabulary indirection | | `hydrate::hydrate` | Counts/addresses verified; unaddressed triples refused | Index-only hydration replacing the TOC, full throughput claim | | `CausalEdge64::ZERO` and S/P/O setters | Grammar-only low 24 bits, *high 40 zero* | Evidence/root persistence and NAL confidence calibration | | `tekamolo::read_clause`, `loci`, `wave` | Explicit future join points | TEKAMOLO x Haspelmath adjudication and 24xi4 anaphora | @@ -70,9 +81,13 @@ local to this research example, not new classid, CE64 or ABI assignments. **Do not conflate:** 1. English *to* vs French *à* is a comparison of multifunctionality, not a mathematical mapping from the lexical word "to" to its WordId neighbors. -2. The lower 24 bits of a CE64 register have three **u8 local** codes here, - not the `u16` `Spo::pack` layout. The sidecar is indispensable and must - be persisted atomically by any future production writer. +2. CE64's three **u8 operand lanes are a versioned ALU/ISA register contract**, + not u16 `Spo::pack` and NOT per-verse tokens. A stable, externally pinned + operand dictionary at the ingest boundary is essential to make codes mean + the same thing for every consumer of the same sealed epoch. Never infer + semantic identity from coincidental byte equality between unaligned versions. + This harness's tiny dictionary is a compatibility fixture, not a new global + codebook authority or a solution for all 65,536 WordIds. 3. Syntax does not deserve f=1, c=1, a Pearl intervention mark, or `EpistemicState5::Causes`. Bare grammar output has no independent witness-based evidence roots. This probe leaves the CE64 header unset. @@ -96,9 +111,9 @@ cargo fmt --manifest-path crates/deepnsm-v2/Cargo.toml --check | HSM-0 | Fig. 8.1 English *to*, German *zu*: connected | Wrong adjacency topology | | HSM-1 | Purpose+judicantis: disjoint | A vacuous "everything is adjacent" map | | HSM-2 | Incomplete function evidence stays `Incomplete` | Mistaking missing linguistic data for contradiction | -| HSM-3 | Single verse FSM → hydrate → CE64 → u16 roundtrip (IDs >255) | Silent `u16 as u8` truncation | +| HSM-3 | Single verse FSM → hydrate → CE64 → u16 roundtrip (IDs >255) using ONE frozen ABI | Silent narrowing and ephemeral relabeling | | HSM-4 | Parser alternatives preserved separately from certain hydrated givens | Silent arbitrary disambiguation | -| HSM-5 | One verse, 258 different IDs | Silent codebook overflow/aliasing | +| HSM-5 | Attempt >256 globally admitted operand codes, or an unknown word | Silent overflow, implicit remap or aliasing | | HSM-6 | Mismatched per-verse markers refused | Cross-verse identity drift | | HSM-7 | Missing evidence source refused | Unsupported evidence annotation | | HSM-8 | CE64 upper bits remain zero | Fabricated NARS/Pearl/epistemic certainty | @@ -121,9 +136,13 @@ Preserve multiplicity, lexical unknowns, scope, ambiguity and signed local pointer overflow. Unbound references escalate instead of being guessed. **Wave C: Hydrated CE64 evidence.** Add a genuinely authorized writer whose -sidecar scope is `(classid, sealed version, verse path)`, preserving -stable word IDs, grammar receipts, original evidence roots, source timestamps, -and read authorization. Require CE64 high-bit interpretations to follow the +shared-ABI scope is `(classid, sealed version, register codebook/version)`, +*not* one codebook per verse. Preserve stable WordIds separately from the +agreed operand ABI, grammar receipts, original evidence roots, source timestamps, +and read authorization. The ABI must be identical for all readers of that +version, with incompatible dictionaries rejected. A full-vocabulary strategy +requires explicit, global indirection or a wider addressing contract; do not +silently redefine the 8:8:8 physical register. Require CE64 high-bit interpretations to follow the current global header contract; no private reassignments. **Wave D: Measurement.** Pin the KJV + Luther corpus snapshots, report @@ -137,13 +156,15 @@ sets to the existing parser oracle before claiming a speedup. - A complete cross-linguistic attestation disconnected on a frozen map: **map falsified**, not an invitation to modify oracle data to fit. -- Broken u16 recovery or local palette overflow: **refuse CE64 projection**. +- Missing canonical register operand or frozen ABI overflow: **refuse CE64 projection**. - Any altered `parse_readings` certain/alternative accounting: **STOP**. - Inference from grammatical contiguity to causality or truth confidence: **STOP**. - Source-root duplication elevating confidence, stale temporal windows, or unauthorized view composition: **STOP**. - A build lacking the relevant production writer: **do not call it wired**. +- A per-verse or per-thought register meaning remap: **STOP**, violates the + interoperability goal (the BF16 / TCP-IP analogy). Related plans: D-HOLO-H12 in #1551, D-ORACLE-0 in #1549, D-HL-5 in #1564, D-MTP-0 in #1555, the DeepNSM-v2 D-LXC experiments From 331f0bba3408943dd2cec8eb4f872d1f1a8ae928 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 16 Oct 2026 00:05:00 +0200 Subject: [PATCH 8/9] fix(clippy): iterate semantic-map adjacency directly --- crates/deepnsm-v2/src/haspelmath.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/deepnsm-v2/src/haspelmath.rs b/crates/deepnsm-v2/src/haspelmath.rs index 86da2b6ae..e3a73f50d 100644 --- a/crates/deepnsm-v2/src/haspelmath.rs +++ b/crates/deepnsm-v2/src/haspelmath.rs @@ -75,9 +75,9 @@ pub fn continuity(functions: u8, coverage_complete: bool) -> MapVerdict { let mut seen = 1u8 << functions.trailing_zeros(); loop { let mut next = seen; - for i in 0..8 { + for (i, &neighbors) in NEIGHBORS.iter().enumerate() { if seen & (1 << i) != 0 { - next |= NEIGHBORS[i] & functions; + next |= neighbors & functions; } } if next == seen { From 86bebdcf88def585afa718148eeb6f6201a81812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=BCbener?= Date: Fri, 16 Oct 2026 02:16:31 +0200 Subject: [PATCH 9/9] fmt: rustfmt haspelmath.rs and haspelmath_wiring.rs (the red `format` check) Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01HJmVZ8oUCaqgZ1efdeqCif --- .../deepnsm-v2/examples/haspelmath_wiring.rs | 15 +++-- crates/deepnsm-v2/src/haspelmath.rs | 55 +++++++++++++------ 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/crates/deepnsm-v2/examples/haspelmath_wiring.rs b/crates/deepnsm-v2/examples/haspelmath_wiring.rs index b66d18f24..b41329233 100644 --- a/crates/deepnsm-v2/examples/haspelmath_wiring.rs +++ b/crates/deepnsm-v2/examples/haspelmath_wiring.rs @@ -38,12 +38,15 @@ fn main() { }; // Register ABI is version-pinned across the entire execution epoch. // This tiny shared dictionary is a fixture, not the deployed global ISA. - let abi = FrozenOperandAbi::new(1, &[ - vocab.id("doctor").unwrap(), - vocab.id("gave").unwrap(), - vocab.id("letter").unwrap(), - vocab.id("to").unwrap(), - ]) + let abi = FrozenOperandAbi::new( + 1, + &[ + vocab.id("doctor").unwrap(), + vocab.id("gave").unwrap(), + vocab.id("letter").unwrap(), + vocab.id("to").unwrap(), + ], + ) .expect("shared dictionary fixture"); let out = run_harness(&[(1, 1)], &[tokens], &[vec![attestation]], 3, &abi) .expect("fixture is addressable"); diff --git a/crates/deepnsm-v2/src/haspelmath.rs b/crates/deepnsm-v2/src/haspelmath.rs index e3a73f50d..60cce105e 100644 --- a/crates/deepnsm-v2/src/haspelmath.rs +++ b/crates/deepnsm-v2/src/haspelmath.rs @@ -45,14 +45,14 @@ impl DativeFunction { // Undirected structural links as printed in Fig. 8.1. // They are hypotheses about neighbors, NOT embedding distances or causal edges. const NEIGHBORS: [u8; 8] = [ - (1 << 1) | (1 << 3), // direction: recipient, purpose + (1 << 1) | (1 << 3), // direction: recipient, purpose (1 << 0) | (1 << 2) | (1 << 4) | (1 << 5), - 1 << 1, // experiencer: recipient - 1 << 0, // purpose: direction + 1 << 1, // experiencer: recipient + 1 << 0, // purpose: direction (1 << 1) | (1 << 6) | (1 << 7), // beneficiary - (1 << 1) | (1 << 6), // predicative possessor - (1 << 4) | (1 << 5), // external possessor - 1 << 4, // judicantis: beneficiary + (1 << 1) | (1 << 6), // predicative possessor + (1 << 4) | (1 << 5), // external possessor + 1 << 4, // judicantis: beneficiary ]; /// Test continuity on the INDUCED graph, not along paths through unlicensed @@ -165,7 +165,11 @@ impl FrozenOperandAbi { return Err(HarnessError::DuplicateCanonicalOperand(word)); } } - Ok(Self { version, operands: operands.to_vec(), by_word }) + Ok(Self { + version, + operands: operands.to_vec(), + by_word, + }) } fn code(&self, word: WordId) -> Result { @@ -310,10 +314,8 @@ mod tests { #[test] fn haspelmath_to_and_zu_are_connected_but_unrelated_pair_is_not() { use DativeFunction as F; - let english_to = F::Direction.bit() - | F::Recipient.bit() - | F::Purpose.bit() - | F::Experiencer.bit(); + let english_to = + F::Direction.bit() | F::Recipient.bit() | F::Purpose.bit() | F::Experiencer.bit(); assert_eq!(continuity(english_to, true), MapVerdict::Connected); assert_eq!( continuity(F::Direction.bit() | F::Purpose.bit(), true), @@ -348,7 +350,10 @@ mod tests { assert_eq!(output.encoded.len(), 1); assert_eq!(output.hydration.triples.len(), 1); let e = &output.encoded[0]; - assert_eq!(output.decode(e, &abi), Some(Spo::new(0x0101, 0x1234, 0xFFFF))); + assert_eq!( + output.decode(e, &abi), + Some(Spo::new(0x0101, 0x1234, 0xFFFF)) + ); let other_version = FrozenOperandAbi::new(8, &[0x0101, 0x1234, 0xFFFF]).unwrap(); assert_eq!(output.decode(e, &other_version), None); assert_eq!(e.order, output.hydration.triples[0].order); @@ -373,10 +378,14 @@ mod tests { run_harness( &[(1, 1)], &[vec![]], - &[vec![FormAttestation { coverage_complete: true, ..att }]], + &[vec![FormAttestation { + coverage_complete: true, + ..att + }]], 1, &abi, - ).err(), + ) + .err(), Some(HarnessError::DisconnectedCompleteDistribution) ); } @@ -395,8 +404,22 @@ mod tests { let abi = FrozenOperandAbi::new(1, &[1, 2, 3, 9]).unwrap(); let r = run_harness(&[(1, 1)], &[tokens], &[vec![]], 2, &abi).unwrap(); assert_eq!(r.ambiguous_tokens, oracle.ambiguous.len()); - assert_eq!(r.alternatives, oracle.alternative.into_iter().map(|s| (0, s)).collect::>()); - assert_eq!(r.hydration.triples.iter().map(|t| t.spo).collect::>(), oracle.certain); + assert_eq!( + r.alternatives, + oracle + .alternative + .into_iter() + .map(|s| (0, s)) + .collect::>() + ); + assert_eq!( + r.hydration + .triples + .iter() + .map(|t| t.spo) + .collect::>(), + oracle.certain + ); } #[test]