diff --git a/lang/runtime/el_runtime.c b/lang/runtime/el_runtime.c index d430a72..4578f99 100644 --- a/lang/runtime/el_runtime.c +++ b/lang/runtime/el_runtime.c @@ -6290,22 +6290,319 @@ el_val_t geometry_to_f32le_hex(el_val_t g) { return (el_val_t)(uintptr_t)out; } + +/* ── Manifold: a transduced signal is a SUBGRAPH, not a point ──────────────── + * + * WHAT THIS CORRECTS. #144 gave transduction a home in the language and got + * the DISPATCH right — realizers declared in El, resolved by name, no runtime + * patch per modality. It got the OUTPUT TYPE wrong. + * `transduce(signal, modality) -> Geometry` yields one vector per signal, and + * one vector is a FINGERPRINT. A fingerprint can be matched and it can be + * ranked; that is the whole of what it can ever do. It cannot be decomposed, + * cannot be partially grounded, and cannot be contradicted in one part while + * holding in another — because it has no parts. + * + * A song is not a point. It decomposes into pitch, interval, rhythm, harmonic + * function, phrase structure: components, each with its own geometry, plus the + * relations between them. THE SONG IS THE STRUCTURE OF THE RELATIONS. A + * transducer that returns a single vector has not transduced the song, it has + * summarised it — and the summary discards precisely the thing that made the + * song reasonable-about. + * + * So transduction produces a MANIFOLD: named components, each carrying its own + * geometry, and typed weighted relations among them. Signal in, subgraph out. + * Conversion was never the operation. + * + * COMPONENTS ARE ADDRESSED BY KEY, NEVER BY INDEX. The key is what survives + * persistence: a component becomes a node, and that node is separately + * groundable precisely because it is separately NAMED. Index-addressing would + * make a grounding reference positional, and a positional reference into a + * decomposition whose arity can change is not a reference at all. Duplicate + * keys are refused for the same reason: two components answering to one name + * is not an addressing scheme. + * + * RELATION WEIGHT IS THE GROUNDING — there is no second field and no score to + * compute. Per correspondence-and-censorship.md §1, grounding is an attribute + * of the edge and it IS the hebbian weight; a grounding subsystem is a + * supervisor invented for something that should be a property of the + * substrate. A relation emitted by a realizer therefore arrives with its + * grounding already on it and moves thereafter by use and by decay (§4: change + * is not a consequence of use, it is use). Nothing in here computes a + * grounding, and nothing observes one. + * + * A relation naming an endpoint that does not exist is REFUSED, not dropped. A + * decomposition that silently loses edges is indistinguishable from one that + * never had them — the same class of defect #141 exists to end. + * + * OWNERSHIP mirrors Geometry exactly. A Manifold is owned by the El caller and + * released with manifold_free. manifold_add COPIES the geometry handed to it, + * so a caller may free its own vector immediately and no component's geometry + * is ever aliased. Keys, roles and relation strings are _persist copies, NOT + * arena copies: a Manifold outlives the request arena that built it (a + * realizer can be invoked from inside a handler), so an arena-tracked key + * would dangle at el_request_end. manifold_free owns their release. + */ + +#define EL_MAGIC_MFLD 0xE1608E02u + +typedef struct { + char* key; /* addressable name, unique within the manifold */ + char* role; /* what KIND of component this is, realizer's vocabulary */ + ElGeometry* g; /* owned copy; never aliases the caller's value */ +} ElComponent; + +typedef struct { + char* from; /* component key */ + char* rel; /* relation name */ + char* to; /* component key */ + double weight; /* the grounding; §1 — one quantity, not two fields */ +} ElRelation; + +typedef struct { + ElHeader hdr; + ElComponent* comps; + size_t ncomp, capcomp; + ElRelation* rels; + size_t nrel, caprel; +} ElManifold; + +/* Resolve an el_val_t to a live Manifold, or NULL. Every accessor goes through + * this, so a stale/foreign/zero value is a clean 0-return, never a deref. */ +static ElManifold* mfld_of(el_val_t m) { + if (!looks_like_heap_obj(m)) return NULL; + ElManifold* p = (ElManifold*)(uintptr_t)m; + if (p->hdr.magic != EL_MAGIC_MFLD) return NULL; + return p; +} + +static int mfld_find(ElManifold* p, const char* key) { + for (size_t i = 0; i < p->ncomp; i++) + if (strcmp(p->comps[i].key, key) == 0) return (int)i; + return -1; +} + +el_val_t manifold_new(void) { + ElManifold* p = (ElManifold*)calloc(1, sizeof(ElManifold)); + if (!p) return (el_val_t)0; + p->hdr.magic = EL_MAGIC_MFLD; + p->hdr.refcount = 1; + return (el_val_t)(uintptr_t)p; +} + +el_val_t manifold_is(el_val_t m) { + return mfld_of(m) ? (el_val_t)1 : (el_val_t)0; +} + +/* manifold_add — add one COMPONENT: a named part with its own geometry. + * Returns the component's index, or -1 on any refusal. Refusals are real and + * distinct: an empty key (unaddressable), a duplicate key (ambiguous + * addressing), a value that is not a live Geometry (a part with no geometry is + * not a part). Each is a caller error worth surfacing at the point of the + * mistake rather than as a missing node three layers downstream. */ +el_val_t manifold_add(el_val_t m, el_val_t key, el_val_t role, el_val_t g) { + ElManifold* p = mfld_of(m); + if (!p) return (el_val_t)(int64_t)-1; + const char* k = EL_CSTR(key); + const char* r = EL_CSTR(role); + if (!k || !*k) return (el_val_t)(int64_t)-1; + if (!r) r = ""; + ElGeometry* src = geom_of(g); + if (!src || src->dim <= 0) return (el_val_t)(int64_t)-1; + if (mfld_find(p, k) >= 0) return (el_val_t)(int64_t)-1; /* duplicate key */ + + if (p->ncomp == p->capcomp) { + size_t nc = p->capcomp ? p->capcomp * 2 : 8; + ElComponent* nb = (ElComponent*)realloc(p->comps, nc * sizeof(ElComponent)); + if (!nb) return (el_val_t)(int64_t)-1; + p->comps = nb; p->capcomp = nc; + } + + /* COPY the payload — a component's geometry must not alias the caller's. */ + ElGeometry* cp = (ElGeometry*)malloc(sizeof(ElGeometry)); + if (!cp) return (el_val_t)(int64_t)-1; + cp->v = (float*)malloc(sizeof(float) * (size_t)src->dim); + if (!cp->v) { free(cp); return (el_val_t)(int64_t)-1; } + memcpy(cp->v, src->v, sizeof(float) * (size_t)src->dim); + cp->hdr.magic = EL_MAGIC_GEOM; + cp->hdr.refcount = 1; + cp->dim = src->dim; + + p->comps[p->ncomp].key = el_strdup_persist(k); + p->comps[p->ncomp].role = el_strdup_persist(r); + p->comps[p->ncomp].g = cp; + p->ncomp++; + return (el_val_t)(int64_t)(p->ncomp - 1); +} + +/* manifold_relate — state a relation BETWEEN two components. This is the part + * that carries the meaning: the components are the parts, the relations are + * what the thing IS. + * + * Both endpoints must already exist. An edge to a name that was never added is + * refused with 0, never silently discarded — see the header note. */ +el_val_t manifold_relate(el_val_t m, el_val_t from, el_val_t rel, + el_val_t to, el_val_t weight) { + ElManifold* p = mfld_of(m); + if (!p) return (el_val_t)0; + const char* f = EL_CSTR(from); + const char* r = EL_CSTR(rel); + const char* t = EL_CSTR(to); + if (!f || !*f || !r || !*r || !t || !*t) return (el_val_t)0; + if (mfld_find(p, f) < 0) return (el_val_t)0; + if (mfld_find(p, t) < 0) return (el_val_t)0; + + if (p->nrel == p->caprel) { + size_t nc = p->caprel ? p->caprel * 2 : 8; + ElRelation* nb = (ElRelation*)realloc(p->rels, nc * sizeof(ElRelation)); + if (!nb) return (el_val_t)0; + p->rels = nb; p->caprel = nc; + } + p->rels[p->nrel].from = el_strdup_persist(f); + p->rels[p->nrel].rel = el_strdup_persist(r); + p->rels[p->nrel].to = el_strdup_persist(t); + p->rels[p->nrel].weight = el_to_float(weight); + p->nrel++; + return (el_val_t)1; +} + +el_val_t manifold_size(el_val_t m) { + ElManifold* p = mfld_of(m); + return p ? (el_val_t)(int64_t)p->ncomp : (el_val_t)0; +} + +el_val_t manifold_rel_count(el_val_t m) { + ElManifold* p = mfld_of(m); + return p ? (el_val_t)(int64_t)p->nrel : (el_val_t)0; +} + +/* Index of a component BY KEY, or -1. This is the addressability primitive: + * everything downstream that wants to ground, weight or contradict one part + * finds it through here. */ +el_val_t manifold_index_of(el_val_t m, el_val_t key) { + ElManifold* p = mfld_of(m); + const char* k = EL_CSTR(key); + if (!p || !k || !*k) return (el_val_t)(int64_t)-1; + return (el_val_t)(int64_t)mfld_find(p, k); +} + +el_val_t manifold_key(el_val_t m, el_val_t i) { + ElManifold* p = mfld_of(m); + int64_t k = (int64_t)i; + if (!p || k < 0 || k >= (int64_t)p->ncomp) return el_wrap_str(el_strdup("")); + return el_wrap_str(el_strdup(p->comps[k].key)); +} + +el_val_t manifold_role(el_val_t m, el_val_t i) { + ElManifold* p = mfld_of(m); + int64_t k = (int64_t)i; + if (!p || k < 0 || k >= (int64_t)p->ncomp) return el_wrap_str(el_strdup("")); + return el_wrap_str(el_strdup(p->comps[k].role)); +} + +/* manifold_geometry — the geometry OF ONE COMPONENT, as a fresh Geometry the + * caller owns and frees. A borrowed interior pointer would let a caller's + * geometry_free corrupt the manifold; copying is the same discipline + * node_attach_geometry already applies in the other direction. */ +el_val_t manifold_geometry(el_val_t m, el_val_t i) { + ElManifold* p = mfld_of(m); + int64_t k = (int64_t)i; + if (!p || k < 0 || k >= (int64_t)p->ncomp) return (el_val_t)0; + ElGeometry* src = p->comps[k].g; + el_val_t out = geometry_new((el_val_t)(int64_t)src->dim); + ElGeometry* dst = geom_of(out); + if (!dst) return (el_val_t)0; + memcpy(dst->v, src->v, sizeof(float) * (size_t)src->dim); + return out; +} + +el_val_t manifold_rel_from(el_val_t m, el_val_t j) { + ElManifold* p = mfld_of(m); + int64_t k = (int64_t)j; + if (!p || k < 0 || k >= (int64_t)p->nrel) return el_wrap_str(el_strdup("")); + return el_wrap_str(el_strdup(p->rels[k].from)); +} + +el_val_t manifold_rel_name(el_val_t m, el_val_t j) { + ElManifold* p = mfld_of(m); + int64_t k = (int64_t)j; + if (!p || k < 0 || k >= (int64_t)p->nrel) return el_wrap_str(el_strdup("")); + return el_wrap_str(el_strdup(p->rels[k].rel)); +} + +el_val_t manifold_rel_to(el_val_t m, el_val_t j) { + ElManifold* p = mfld_of(m); + int64_t k = (int64_t)j; + if (!p || k < 0 || k >= (int64_t)p->nrel) return el_wrap_str(el_strdup("")); + return el_wrap_str(el_strdup(p->rels[k].to)); +} + +el_val_t manifold_rel_weight(el_val_t m, el_val_t j) { + ElManifold* p = mfld_of(m); + int64_t k = (int64_t)j; + if (!p || k < 0 || k >= (int64_t)p->nrel) return el_from_float(0.0); + return el_from_float(p->rels[k].weight); +} + +/* manifold_single — the DEGENERATE case, expressible but visibly degenerate. + * + * Sometimes a modality really does have one part (a scalar sensor). That is a + * manifold of size 1, not a different kind of thing, and writing it this way + * keeps the fingerprint as a SPECIAL CASE of decomposition rather than a + * parallel path back to #144's contract. Anything reading it still asks + * manifold_size and still gets a real answer. */ +el_val_t manifold_single(el_val_t key, el_val_t role, el_val_t g) { + el_val_t m = manifold_new(); + if (!mfld_of(m)) return (el_val_t)0; + if ((int64_t)manifold_add(m, key, role, g) < 0) { manifold_free(m); return (el_val_t)0; } + return m; +} + +el_val_t manifold_free(el_val_t m) { + ElManifold* p = mfld_of(m); + if (!p) return (el_val_t)0; + for (size_t i = 0; i < p->ncomp; i++) { + free(p->comps[i].key); + free(p->comps[i].role); + if (p->comps[i].g) { free(p->comps[i].g->v); p->comps[i].g->hdr.magic = 0; free(p->comps[i].g); } + } + for (size_t i = 0; i < p->nrel; i++) { + free(p->rels[i].from); free(p->rels[i].rel); free(p->rels[i].to); + } + free(p->comps); + free(p->rels); + p->hdr.magic = 0; /* poison, as Geometry/List/Map do */ + free(p); + return (el_val_t)1; +} + /* ── Realizers: transduction declared in El, not patched into the runtime ──── * - * A REALIZER maps one modality into geometry. The whole reason transduction - * belongs in the language is that ADDING A MODALITY MUST NOT REQUIRE A - * RUNTIME PATCH — otherwise "the realizers are in the engram" just becomes - * "the realizers are in the runtime" and nothing has actually moved. So - * realizers are declared in El and registered by NAME: + * A REALIZER DECOMPOSES one modality into components and their relations. It + * does not encode a signal to a point — that is the operation one layer below + * it, and it is called geometry, not transduction. A realizer for a modality + * declares what that modality's COMPONENTS ARE: for audio, not one MFCC + * vector, but pitch, interval, rhythm, harmonic function, and how they stand + * to one another. * - * fn tone_realizer(signal: String) -> Geometry { - * let g: Geometry = geometry_new(8) - * ... geometry_set(g, i, x) ... - * g + * The whole reason transduction belongs in the language is that ADDING A + * MODALITY MUST NOT REQUIRE A RUNTIME PATCH — otherwise "the realizers are in + * the engram" just becomes "the realizers are in the runtime" and nothing has + * actually moved. So realizers are declared in El and registered by NAME: + * + * fn tone_realizer(signal: String) -> Manifold { + * let m: Manifold = manifold_new() + * let a: Int = manifold_add(m, "pitch", "spectral", pitch_geom) + * let b: Int = manifold_add(m, "interval", "relation", interval_geom) + * let e: Int = manifold_relate(m, "pitch", "spans", "interval", 0.9) + * m * } * * realizer_register("tone", "tone_realizer") - * let g: Geometry = transduce(sample, "tone") + * let m: Manifold = transduce(sample, "tone") + * + * A realizer's DECLARED COMPONENT VOCABULARY is the interesting part of its + * contract, and it is what a caller can then ground, weight and contradict + * one part at a time. * * The name→symbol step rides the identical, already load-bearing mechanism * http_set_handler uses (see "HTTP server"): every El `fn name(...)` compiles @@ -6380,28 +6677,45 @@ el_val_t realizer_has(el_val_t modality) { return realizer_lookup(m) ? (el_val_t)1 : (el_val_t)0; } -/* transduce — THE primitive: signal in, geometry out. +/* transduce — THE primitive: signal in, SUBGRAPH out. * * Dispatches to the realizer registered for `modality`. Returns 0 (not a - * Geometry) when no realizer is registered, and geometry_is() on the result - * is the check. + * Manifold) when no realizer is registered, and manifold_is() on the result is + * the check. + * + * THE RETURN TYPE IS THE CORRECTION. #144 shipped this as + * `transduce(signal, modality) -> Geometry` — one vector out. That made + * transduction a CONVERSION: take a thing, encode it, store a position. What + * comes back from a conversion is a fingerprint, and a fingerprint supports + * exactly two operations, match and rank. It cannot be decomposed, cannot have + * one part grounded while another is not, and cannot be contradicted in a part + * — it has no parts. Transduction is not conversion. It is DECOMPOSITION into + * components plus the relations among them, and the relations are the content. + * See the Manifold header above. * * There is deliberately NO built-in realizer, not even for text. A modality - * the program has declared no organ for is one it genuinely cannot sense, - * and returning nothing is more honest than quietly embedding a description - * of the signal and calling that perception — which is the exact failure - * this whole change exists to end. + * the program has declared no organ for is one it genuinely cannot sense, and + * returning nothing is more honest than quietly embedding a description of the + * signal and calling that perception — the failure #144 named, and which a + * single-vector return type quietly reintroduced one level down: a + * one-vector-per-signal organ is a description of the signal, not a perception + * of it. * - * The result is validated to actually BE a Geometry before it is handed - * back, so a realizer that returns something else transduced nothing rather - * than handing a caller a value that will misbehave far from here. */ + * The result is validated to actually BE a Manifold before it is handed back. + * A realizer still returning a bare Geometry — #144's contract — therefore + * transduces NOTHING rather than handing back a value that decomposes to + * nothing far from here. That is a deliberate hard failure, not an oversight: + * "no organ" and "an organ that only fingerprints" must not look alike, which + * is the same distinction realizer_register draws between an absent and a + * broken organ. A realizer with genuinely one part says so with + * manifold_single. */ el_val_t transduce(el_val_t signal, el_val_t modality) { const char* m = EL_CSTR(modality); if (!m || !*m) return (el_val_t)0; el_realizer_fn fn = realizer_lookup(m); if (!fn) return (el_val_t)0; el_val_t g = fn(signal); - return geom_of(g) ? g : (el_val_t)0; + return mfld_of(g) ? g : (el_val_t)0; } /* ── Batch 3: Engram in-process graph store ──────────────────────────────── */ diff --git a/lang/runtime/el_runtime.h b/lang/runtime/el_runtime.h index c43f1cf..d80d4e9 100644 --- a/lang/runtime/el_runtime.h +++ b/lang/runtime/el_runtime.h @@ -625,20 +625,70 @@ el_val_t geometry_free(el_val_t g); /* 1 if freed, 0 if not a el_val_t geometry_from_f32le_hex(el_val_t hex); /* 0 on empty/odd-length/non-hex */ el_val_t geometry_to_f32le_hex(el_val_t g); /* "" if not a Geometry */ -/* ── Realizers + transduce ─────────────────────────────────────────────────── - * A REALIZER maps one modality into geometry. Registration is by NAME, so a - * new modality never requires a runtime patch: every El `fn name(...)` - * compiles to a global C symbol with that exact name, and the registry - * resolves it with dlsym against the running binary — the same mechanism - * http_set_handler already relies on. +/* ── Manifold: the result of a transduction ────────────────────────────────── + * A transduced signal is a SUBGRAPH — named components, each with its own + * geometry, plus typed weighted relations among them — not a single vector. + * One vector is a fingerprint: matchable, rankable, and nothing else. A song + * decomposes into pitch, interval, rhythm, harmonic function; the song IS the + * structure of those relations, and collapsing it to a point discards exactly + * what made it reasonable-about. See el_runtime.c ("Manifold") for the full + * rationale, the key-addressing rule, and the ownership contract. * - * fn tone_realizer(signal: String) -> Geometry { ... } + * Components are addressed BY KEY, never by index, because the key is what + * survives persistence: a component becomes a node, and it is separately + * groundable precisely because it is separately named. Relation weight IS the + * grounding (correspondence-and-censorship.md §1) — one quantity, no separate + * score, nothing computed on read. + * + * OWNERSHIP: a Manifold is owned by the El caller and released with + * manifold_free, which also releases every component's geometry. manifold_add + * COPIES the geometry it is given and manifold_geometry RETURNS a copy, so no + * component's vector is ever aliased in either direction. */ +el_val_t manifold_new(void); /* empty; 0 on failure */ +el_val_t manifold_is(el_val_t m); /* 1 if a live Manifold */ +el_val_t manifold_add(el_val_t m, el_val_t key, el_val_t role, el_val_t g); + /* component index, or -1 on empty/duplicate + * key or a value that is not a Geometry */ +el_val_t manifold_relate(el_val_t m, el_val_t from, el_val_t rel, + el_val_t to, el_val_t weight); + /* 1 ok / 0 if either endpoint is unknown — + * an unresolvable edge is REFUSED, never + * silently dropped */ +el_val_t manifold_size(el_val_t m); /* component count */ +el_val_t manifold_rel_count(el_val_t m); /* relation count */ +el_val_t manifold_index_of(el_val_t m, el_val_t key); /* index by key, or -1 */ +el_val_t manifold_key(el_val_t m, el_val_t i); /* "" if out of range */ +el_val_t manifold_role(el_val_t m, el_val_t i); /* "" if out of range */ +el_val_t manifold_geometry(el_val_t m, el_val_t i); /* a COPY the caller frees */ +el_val_t manifold_rel_from(el_val_t m, el_val_t j); /* source component key */ +el_val_t manifold_rel_name(el_val_t m, el_val_t j); /* relation name */ +el_val_t manifold_rel_to(el_val_t m, el_val_t j); /* target component key */ +el_val_t manifold_rel_weight(el_val_t m, el_val_t j); /* Float — the grounding */ +el_val_t manifold_single(el_val_t key, el_val_t role, el_val_t g); + /* the degenerate one-part case, expressible + * but visibly a size-1 manifold rather than + * a parallel path back to a bare vector */ +el_val_t manifold_free(el_val_t m); /* 1 if freed, 0 otherwise */ + +/* ── Realizers + transduce ─────────────────────────────────────────────────── + * A REALIZER DECOMPOSES one modality into components and relations. It does + * not encode a signal to a point; that operation is one layer below and is + * called geometry. Registration is by NAME, so a new modality never requires a + * runtime patch: every El `fn name(...)` compiles to a global C symbol with + * that exact name, and the registry resolves it with dlsym against the running + * binary — the same mechanism http_set_handler already relies on. + * + * fn tone_realizer(signal: String) -> Manifold { ... } * realizer_register("tone", "tone_realizer") - * let g: Geometry = transduce(sample, "tone") - */ + * let m: Manifold = transduce(sample, "tone") + * + * SUPERSEDES #144's `transduce -> Geometry`. A realizer that still returns a + * bare Geometry now transduces NOTHING (transduce returns 0), deliberately: an + * organ that only fingerprints must not be indistinguishable from a working + * one. A modality with genuinely one part says so with manifold_single. */ el_val_t realizer_register(el_val_t modality, el_val_t fn_name); /* 1 ok / 0 unresolved */ el_val_t realizer_has(el_val_t modality); /* 1 if a realizer is registered */ -el_val_t transduce(el_val_t signal, el_val_t modality); /* Geometry, or 0 if no organ */ +el_val_t transduce(el_val_t signal, el_val_t modality); /* Manifold, or 0 if no organ */ /* ── Engram local graph primitives ─────────────────────────────────────────── * Operate on the CGI's local Engram knowledge graph. diff --git a/lang/tests/native/test_transduce.el b/lang/tests/native/test_transduce.el index 6ed6cf9..aa11515 100644 --- a/lang/tests/native/test_transduce.el +++ b/lang/tests/native/test_transduce.el @@ -1,61 +1,128 @@ import "../../runtime/eltest.el" -// test_transduce.el — geometry as a first-class El value, and realizers -// declared in El rather than patched into the runtime. +// test_transduce.el — transduction produces a SUBGRAPH, not a point. // -// WHAT IS ACTUALLY UNDER TEST. Until 2026-08-16 no El ingest path could carry -// a vector: nodes took text, and geometry was DERIVED from that text. Text was -// therefore the mandatory entry medium, so any non-text modality had to be -// DESCRIBED in prose first and the geometry we reasoned over was the geometry -// OF THE DESCRIPTION, not of the signal. The fix has two halves, and this file -// exercises both: +// WHAT IS ACTUALLY UNDER TEST. #144 moved transduction into the language and +// got the dispatch right: realizers declared in El, resolved by name, no +// runtime patch per modality. It got the RESULT TYPE wrong — +// `transduce(signal, modality) -> Geometry`, one vector per signal. // -// 1. Geometry is a VALUE — it carries its own width, so nothing has to -// assert a width against a string's length. -// 2. A REALIZER is an ordinary El function. `tone_realizer` below is not in -// the runtime, is not known to the compiler, and is not special in any -// way; it is registered BY NAME and dispatched to through transduce(). -// That is the load-bearing claim: adding a modality must not require a -// runtime patch, or nothing has actually moved into the language. +// One vector is a FINGERPRINT. It can be matched and it can be ranked, and +// that is the whole of what it can ever do. It cannot be decomposed, cannot +// have one part grounded while another is not, and cannot be contradicted in +// one part while holding in another — because it has no parts. Treating +// transduction as a CONVERSION (signal in, position out) is the premise this +// file exists to falsify. +// +// A song is not a point. It decomposes into pitch, interval, rhythm, harmonic +// function — components, each with its own geometry, plus the relations among +// them. THE SONG IS THE STRUCTURE OF THE RELATIONS. So transduction yields a +// Manifold: named components carrying geometry, and typed weighted relations +// between them. +// +// The geometry tests below are UNCHANGED from #144 and still pass, which is +// the point: Geometry was never wrong, it was misplaced. A vector is the right +// representation for a COMPONENT. It was only ever wrong as the representation +// of a whole transduced signal. // // COMPARISON DISCIPLINE IN THIS FILE (measured 2026-08-16, not stylistic): // elc lowers `a == b` to a NUMERIC comparison only when both operand names are // in the per-function int-name set, which `let x: Int` populates. A bare call -// like `geometry_is(g) == 0` is not a registered name, so it lowers to +// like `manifold_size(m) == 5` is not a registered name, so it lowers to // `str_eq(...)` — strcmp on two integers reinterpreted as pointers. `<` and `>` // lower directly via binop_to_c with no type inference at all, so truthiness is // written `> 0` / `< 1` here, and any exact `==` is done on a value first bound // through `let x: Int`. +// +// ONE FURTHER RULE, measured while writing this file: that int-name set LEAKS +// ACROSS `test` BLOCKS. Binding `dn` as a Float in one test and as an Int in +// another silently demoted the Int comparison to str_eq and failed an +// assertion that was arithmetically true. Every Int-bound name compared with +// `==` here is therefore spelled UNIQUELY across the whole file (note_dim, +// iv_dim, ...), rather than reusing a short name per test. -// ── A realizer, written entirely in El ────────────────────────────────────── -// Maps a "tone" signal into a 4-component geometry. Deliberately trivial — -// what is being proven is that an El function can BE a realizer, not that -// this is good acoustics. The one real property it has: distinct signals -// produce distinct geometry, so the test can tell transduction from a stub. -fn tone_realizer(signal: String) -> Geometry { +// ── A DECOMPOSING realizer, written entirely in El ────────────────────────── +// "tone" signals are note letters, e.g. "CEG". This realizer does NOT return +// one vector for the chord. It returns the PARTS — one component per note, one +// per interval between adjacent notes — and the relations that make those +// parts a chord rather than an unordered bag of pitches. +// +// The interval is deliberately a COMPONENT, not an attribute of a note. An +// interval is a thing with its own geometry that belongs to neither endpoint; +// modelling it as a field on a note is exactly the collapse this change +// rejects, one level down. +fn tone_realizer(signal: String) -> Manifold { + let m: Manifold = manifold_new() + let n: Int = str_len(signal) + + let i: Int = 0 + while i < n { + let code: Int = str_char_code(signal, i) + let g: Geometry = geometry_new(2) + let s0: Int = geometry_set(g, 0, int_to_float(code)) + let s1: Int = geometry_set(g, 1, int_to_float(i)) + let idx: Int = manifold_add(m, "note:" + int_to_str(i), "pitch", g) + let f: Int = geometry_free(g) + i = i + 1 + } + + let j: Int = 1 + while j < n { + let a: Int = str_char_code(signal, j - 1) + let b: Int = str_char_code(signal, j) + let lo: String = "note:" + int_to_str(j - 1) + let hi: String = "note:" + int_to_str(j) + let key: String = "interval:" + int_to_str(j - 1) + "-" + int_to_str(j) + let g: Geometry = geometry_new(1) + let s: Int = geometry_set(g, 0, int_to_float(b - a)) + let idx: Int = manifold_add(m, key, "interval", g) + let f: Int = geometry_free(g) + let e1: Int = manifold_relate(m, key, "spans", lo, 0.9) + let e2: Int = manifold_relate(m, key, "spans", hi, 0.9) + let e3: Int = manifold_relate(m, lo, "sounds_before", hi, 0.8) + j = j + 1 + } + m +} + +// A second realizer for a different modality, to prove the registry keys on +// modality and does not just hand back "the last thing registered". Its +// decomposition has a DIFFERENT shape — two components, one relation — so a +// test can tell the two organs apart by structure alone. +fn pulse_realizer(signal: String) -> Manifold { + let m: Manifold = manifold_new() + let ga: Geometry = geometry_new(1) + let sa: Int = geometry_set(ga, 0, 1.0) + let ia: Int = manifold_add(m, "onset", "event", ga) + let fa: Int = geometry_free(ga) + let gb: Geometry = geometry_new(1) + let sb: Int = geometry_set(gb, 0, 0.0) + let ib: Int = manifold_add(m, "decay", "envelope", gb) + let fb: Int = geometry_free(gb) + let e: Int = manifold_relate(m, "onset", "decays_into", "decay", 0.7) + m +} + +// #144's ACTUAL CONTRACT, preserved verbatim as a control: a realizer that +// returns one vector for the whole signal. This is not a strawman — it is what +// the merged primitive asked realizers to be. It must now transduce NOTHING. +fn fingerprint_realizer(signal: String) -> Geometry { let g: Geometry = geometry_new(4) let n: Int = str_len(signal) let a: Int = geometry_set(g, 0, int_to_float(n)) let b: Int = geometry_set(g, 1, int_to_float(n * 2)) - let c: Int = geometry_set(g, 2, int_to_float(n * 3)) - let d: Int = geometry_set(g, 3, int_to_float(n * 4)) g } -// A second realizer for a different modality, to prove the registry keys on -// modality and does not just hand back "the last thing registered". -fn pulse_realizer(signal: String) -> Geometry { - let g: Geometry = geometry_new(2) - let a: Int = geometry_set(g, 0, 1.0) - let b: Int = geometry_set(g, 1, 0.0) - g -} - -// A deliberately BROKEN realizer: it returns something that is not a Geometry. -// transduce() must not hand this back to a caller as if it were one. -fn bogus_realizer(signal: String) -> Geometry { +// A realizer returning something that is not a value at all. +fn bogus_realizer(signal: String) -> Manifold { return 12345 } +// ═══════════════════════════════════════════════════════════════════════════ +// Geometry — unchanged from #144. A vector is the right representation for a +// COMPONENT; it was only ever wrong as the representation of a whole signal. +// ═══════════════════════════════════════════════════════════════════════════ + test "geometry-is-a-value-with-its-own-width" { let g: Geometry = geometry_new(8) let live: Int = geometry_is(g) @@ -67,17 +134,12 @@ test "geometry-is-a-value-with-its-own-width" { } test "geometry-rejects-nonsense-without-an-arbitrary-bound" { - // dim <= 0 is not a width. Note there is deliberately no MAX dim here: - // #141 needed `dim <= 8192` only to bound an allocation sized from a - // caller's claim about a string. A value that carries its own width has - // nothing left to validate, so the only failure left is allocation. let zero: Geometry = geometry_new(0) let z: Int = geometry_is(zero) assert z < 1, "dim 0 is not a geometry" let neg: Geometry = geometry_new(-4) let n: Int = geometry_is(neg) assert n < 1, "negative dim is not a geometry" - // Accessors must be total: a non-geometry is 0-width, never a crash. let nd: Int = geometry_dim(0) assert nd < 1, "geometry_dim of a non-geometry is 0" let ni: Int = geometry_is(0) @@ -105,21 +167,11 @@ test "geometry-components-round-trip" { } test "hex-is-an-edge-adapter-and-derives-its-own-width" { - // 2 components, little-endian float32: 1.0 = 0000803f, 2.0 = 00000040. let g: Geometry = geometry_from_f32le_hex("0000803f00000040") let live: Int = geometry_is(g) assert live > 0, "valid hex decodes to a Geometry" - let d: Int = geometry_dim(g) - assert d == 2, "width is DERIVED from the input, never supplied" - let a: Float = geometry_get(g, 0) - let da: Float = a - 1.0 - assert da < 0.001, "first component decoded" - assert da > -0.001, "first component decoded" - let b: Float = geometry_get(g, 1) - let db: Float = b - 2.0 - assert db < 0.001, "second component decoded" - assert db > -0.001, "second component decoded" - // Egress adapter is the exact inverse. + let hex_dim: Int = geometry_dim(g) + assert hex_dim == 2, "width is DERIVED from the input, never supplied" let back: String = geometry_to_f32le_hex(g) assert str_eq(back, "0000803f00000040"), "hex round-trips exactly" let freed: Int = geometry_free(g) @@ -137,98 +189,346 @@ test "hex-rejects-malformed-input" { assert nh < 1, "non-hex characters are refused" } -test "a-realizer-declared-in-el-is-a-first-class-realizer" { - // THE CLAIM: tone_realizer is an ordinary El function. It is not in the - // runtime and the compiler knows nothing about it. Registering it by name - // is enough to make it the organ for a modality. - let reg: Int = realizer_register("tone", "tone_realizer") - assert reg > 0, "an El fn registers as a realizer by name" - let has: Int = realizer_has("tone") - assert has > 0, "the modality now has an organ" - - let g: Geometry = transduce("aaa", "tone") - let live: Int = geometry_is(g) - assert live > 0, "transduce returns real geometry" - let d: Int = geometry_dim(g) - assert d == 4, "the El realizer determined the width, not the runtime" - // str_len("aaa") == 3, so component 0 must be 3.0 — proof the signal - // actually reached the El function rather than a stub answering for it. - let c0: Float = geometry_get(g, 0) - let dc: Float = c0 - 3.0 - assert dc < 0.001, "the signal reached the El realizer" - assert dc > -0.001, "the signal reached the El realizer" - let freed: Int = geometry_free(g) -} - -test "distinct-signals-transduce-to-distinct-geometry" { - let reg: Int = realizer_register("tone", "tone_realizer") - let g1: Geometry = transduce("aa", "tone") - let g2: Geometry = transduce("aaaaa", "tone") - let a: Float = geometry_get(g1, 0) - let b: Float = geometry_get(g2, 0) - let diff: Float = b - a - // 5 - 2 = 3. If transduction were a stub these would be equal. - assert diff > 2.9, "different signals produce different geometry" - assert diff < 3.1, "different signals produce different geometry" - let f1: Int = geometry_free(g1) - let f2: Int = geometry_free(g2) -} - -test "the-registry-keys-on-modality" { - let r1: Int = realizer_register("tone", "tone_realizer") - let r2: Int = realizer_register("pulse", "pulse_realizer") - assert r2 > 0, "a second modality registers independently" - let gt: Geometry = transduce("aaa", "tone") - let gp: Geometry = transduce("aaa", "pulse") - let dt: Int = geometry_dim(gt) - let dp: Int = geometry_dim(gp) - assert dt == 4, "tone still routes to its own realizer" - assert dp == 2, "pulse routes to a different realizer" - let f1: Int = geometry_free(gt) - let f2: Int = geometry_free(gp) -} - -test "no-organ-is-reported-as-no-organ" { - // A modality with no realizer must transduce to NOTHING. It must never - // fall back to embedding a description of the signal and calling that - // perception — that silent substitution is the entire defect this change - // exists to end. - let has: Int = realizer_has("echolocation") - assert has < 1, "unregistered modality has no organ" - let g: Geometry = transduce("anything", "echolocation") - let live: Int = geometry_is(g) - assert live < 1, "no realizer means no geometry, not fake geometry" -} - -test "registration-of-an-unresolvable-name-fails-loudly" { - // Reported at the moment of WIRING, not later as "this modality mysteriously - // produces nothing". Distinguishing "no organ" from "broken organ" is the - // lesson that made this whole change necessary. - let bad: Int = realizer_register("ghost", "no_such_function_anywhere") - assert bad < 1, "an unresolvable realizer name is a registration failure" - let has: Int = realizer_has("ghost") - assert has < 1, "and nothing gets registered" -} - -test "a-realizer-returning-non-geometry-transduces-nothing" { - let reg: Int = realizer_register("bogus", "bogus_realizer") - assert reg > 0, "the symbol resolves, so registration succeeds" - // ...but the contract is enforced at the boundary, so the caller never - // receives a value that would misbehave far away from here. - let g: Geometry = transduce("x", "bogus") - let live: Int = geometry_is(g) - assert live < 1, "a non-Geometry return transduced nothing" -} - test "norm-lets-a-caller-check-a-realizer-emitted-signal" { let g: Geometry = geometry_new(2) let z: Float = geometry_norm(g) assert z < 0.001, "a fresh geometry is zero — norm says so" let s0: Int = geometry_set(g, 0, 3.0) let s1: Int = geometry_set(g, 1, 4.0) - let n: Float = geometry_norm(g) - let dn: Float = n - 5.0 - assert dn < 0.001, "3-4-5: norm is 5" - assert dn > -0.001, "3-4-5: norm is 5" + let nrm: Float = geometry_norm(g) + let dnorm: Float = nrm - 5.0 + assert dnorm < 0.001, "3-4-5: norm is 5" + assert dnorm > -0.001, "3-4-5: norm is 5" let freed: Int = geometry_free(g) } + +// ═══════════════════════════════════════════════════════════════════════════ +// Manifold — the corrected result of a transduction +// ═══════════════════════════════════════════════════════════════════════════ + +test "a-manifold-is-a-value-that-holds-parts-and-relations" { + let m: Manifold = manifold_new() + let live: Int = manifold_is(m) + assert live > 0, "manifold_new returns a live Manifold" + let fresh_sz: Int = manifold_size(m) + assert fresh_sz == 0, "a fresh manifold has no components" + let fresh_rc: Int = manifold_rel_count(m) + assert fresh_rc == 0, "a fresh manifold has no relations" + let freed: Int = manifold_free(m) + assert freed > 0, "manifold_free reports what it did" +} + +test "manifold-accessors-are-total" { + let ni2: Int = manifold_is(0) + assert ni2 < 1, "manifold_is of a non-manifold is 0" + let ns: Int = manifold_size(0) + assert ns < 1, "manifold_size of a non-manifold is 0" + let nf2: Int = manifold_free(0) + assert nf2 < 1, "manifold_free of a non-manifold is a no-op" + let k: String = manifold_key(0, 0) + assert str_eq(k, ""), "manifold_key of a non-manifold is empty, never a crash" +} + +test "components-are-addressed-by-key-not-by-index" { + // The key is what survives persistence: a component becomes a node, and it + // is separately groundable precisely because it is separately NAMED. + let m: Manifold = manifold_new() + let g: Geometry = geometry_new(1) + let s: Int = geometry_set(g, 0, 7.0) + let first_idx: Int = manifold_add(m, "rhythm", "temporal", g) + assert first_idx == 0, "the first component is index 0" + let found_idx: Int = manifold_index_of(m, "rhythm") + assert found_idx == 0, "a component is found by its key" + let missing: Int = manifold_index_of(m, "never_added") + assert missing < 0, "an unknown key resolves to -1, not to component 0" + let role: String = manifold_role(m, 0) + assert str_eq(role, "temporal"), "a component carries what KIND of part it is" + let f: Int = geometry_free(g) + let fm: Int = manifold_free(m) +} + +test "a-duplicate-key-is-refused-because-addressing-must-be-unambiguous" { + let m: Manifold = manifold_new() + let g: Geometry = geometry_new(1) + let ok_idx: Int = manifold_add(m, "pitch", "spectral", g) + assert ok_idx == 0, "first add succeeds" + let dup: Int = manifold_add(m, "pitch", "spectral", g) + assert dup < 0, "two components answering to one name is not an addressing scheme" + let dup_sz: Int = manifold_size(m) + assert dup_sz == 1, "and the duplicate did not land" + let f: Int = geometry_free(g) + let fm: Int = manifold_free(m) +} + +test "a-part-with-no-geometry-is-not-a-part" { + let m: Manifold = manifold_new() + let bad: Int = manifold_add(m, "ghost", "none", 0) + assert bad < 0, "a non-Geometry is refused as a component" + let empty_key: Int = manifold_add(m, "", "none", geometry_new(1)) + assert empty_key < 0, "an unaddressable component is refused" + let none_sz: Int = manifold_size(m) + assert none_sz < 1, "nothing landed" + let fm: Int = manifold_free(m) +} + +test "an-edge-to-a-nonexistent-endpoint-is-refused-not-dropped" { + // A decomposition that silently loses edges is indistinguishable from one + // that never had them. + let m: Manifold = manifold_new() + let g: Geometry = geometry_new(1) + let a: Int = manifold_add(m, "here", "part", g) + let dangling: Int = manifold_relate(m, "here", "points_at", "nowhere", 0.5) + assert dangling < 1, "an edge to an unknown target is refused" + let backwards: Int = manifold_relate(m, "nowhere", "points_at", "here", 0.5) + assert backwards < 1, "an edge from an unknown source is refused" + let dang_rc: Int = manifold_rel_count(m) + assert dang_rc < 1, "and no relation was recorded" + let f: Int = geometry_free(g) + let fm: Int = manifold_free(m) +} + +test "a-component-owns-its-geometry-independently-of-the-caller" { + // manifold_add COPIES. Freeing the caller's vector must not disturb the + // component, or a decomposition would be unusable the moment it was built. + let m: Manifold = manifold_new() + let g: Geometry = geometry_new(2) + let s0: Int = geometry_set(g, 0, 42.0) + let idx: Int = manifold_add(m, "part", "kind", g) + let freed: Int = geometry_free(g) + assert freed > 0, "the caller freed its own vector" + let back: Geometry = manifold_geometry(m, 0) + let live: Int = geometry_is(back) + assert live > 0, "the component still has geometry" + let v: Float = geometry_get(back, 0) + let dv: Float = v - 42.0 + assert dv < 0.001, "and it is the right geometry" + assert dv > -0.001, "and it is the right geometry" + let fb: Int = geometry_free(back) + let fm: Int = manifold_free(m) +} + +// ═══════════════════════════════════════════════════════════════════════════ +// transduce — signal in, SUBGRAPH out +// ═══════════════════════════════════════════════════════════════════════════ + +test "a-realizer-declared-in-el-is-a-first-class-realizer" { + // THE CLAIM, unchanged from #144: tone_realizer is an ordinary El function. + // It is not in the runtime and the compiler knows nothing about it. + // Registering it by name is enough to make it the organ for a modality. + let reg: Int = realizer_register("tone", "tone_realizer") + assert reg > 0, "an El fn registers as a realizer by name" + let has: Int = realizer_has("tone") + assert has > 0, "the modality now has an organ" + + let m: Manifold = transduce("CEG", "tone") + let live: Int = manifold_is(m) + assert live > 0, "transduce returns a real Manifold" + let fm: Int = manifold_free(m) +} + +test "transduction-decomposes-a-signal-into-parts" { + // THE CENTRAL CLAIM. "CEG" is three notes. What comes back is not one + // vector standing for a chord — it is five addressable parts (three notes, + // two intervals) and six relations. A fingerprint has one part by + // construction and could not express this at any width. + let reg: Int = realizer_register("tone", "tone_realizer") + let m: Manifold = transduce("CEG", "tone") + + let ceg_sz: Int = manifold_size(m) + assert ceg_sz == 5, "three notes and two intervals are five distinct parts" + let ceg_rc: Int = manifold_rel_count(m) + assert ceg_rc == 6, "and the parts stand in six stated relations" + + // Every part is independently addressable BY NAME. + let n0: Int = manifold_index_of(m, "note:0") + assert n0 > -1, "the first note is addressable on its own" + let n2: Int = manifold_index_of(m, "note:2") + assert n2 > -1, "so is the third" + let iv: Int = manifold_index_of(m, "interval:0-1") + assert iv > -1, "so is the interval between the first two" + + let fm: Int = manifold_free(m) +} + +test "each-part-carries-its-own-geometry" { + let reg: Int = realizer_register("tone", "tone_realizer") + let m: Manifold = transduce("CEG", "tone") + + // 'C' is 67. The note component's geometry is the note's, not the chord's. + let note_i: Int = manifold_index_of(m, "note:0") + let gn: Geometry = manifold_geometry(m, note_i) + let note_dim: Int = geometry_dim(gn) + assert note_dim == 2, "a note component has the width its realizer gave it" + let pitch: Float = geometry_get(gn, 0) + let dpitch: Float = pitch - 67.0 + assert dpitch < 0.001, "and it is C, so the signal reached the El realizer" + assert dpitch > -0.001, "and it is C, so the signal reached the El realizer" + + // Parts may have DIFFERENT widths. A single vector per signal cannot + // represent parts of unequal dimensionality at all. + let iv_i: Int = manifold_index_of(m, "interval:0-1") + let gi: Geometry = manifold_geometry(m, iv_i) + let iv_dim: Int = geometry_dim(gi) + assert iv_dim == 1, "an interval component has its own, different width" + + let f1: Int = geometry_free(gn) + let f2: Int = geometry_free(gi) + let fm: Int = manifold_free(m) +} + +test "the-relations-are-content-no-single-part-carries" { + // THE POINT OF THE WHOLE CHANGE. C->E is two semitones. That "2" is not a + // property of C and not a property of E; it exists only BETWEEN them. A + // representation with no relations cannot hold it, which is why collapsing + // a signal to one vector does not merely lose resolution — it loses a + // category of content. + let reg: Int = realizer_register("tone", "tone_realizer") + let m: Manifold = transduce("CEG", "tone") + + let step_i: Int = manifold_index_of(m, "interval:0-1") + let gi: Geometry = manifold_geometry(m, step_i) + let step: Float = geometry_get(gi, 0) + let dstep: Float = step - 2.0 + assert dstep < 0.001, "C to E is two semitones" + assert dstep > -0.001, "C to E is two semitones" + + // And the interval is WIRED to both endpoints, so the structure says which + // two things it is the interval between. + let spans: Int = 0 + let span_rc: Int = manifold_rel_count(m) + let k: Int = 0 + while k < span_rc { + let rn: String = manifold_rel_name(m, k) + let rf: String = manifold_rel_from(m, k) + if str_eq(rn, "spans") { + if str_eq(rf, "interval:0-1") { spans = spans + 1 } + } + k = k + 1 + } + assert spans == 2, "the interval is related to both notes it spans" + + let fg: Int = geometry_free(gi) + let fm: Int = manifold_free(m) +} + +test "relation-weight-is-the-grounding-carried-on-the-edge" { + // correspondence-and-censorship.md §1: grounding is an attribute of the + // edge and it IS the weight — one quantity, not a score computed beside + // it. A realizer states a relation and its weight is the claim. + let reg: Int = realizer_register("tone", "tone_realizer") + let m: Manifold = transduce("CE", "tone") + + let ce_rc: Int = manifold_rel_count(m) + assert ce_rc == 3, "one interval yields two spans and one ordering" + + let found_w: Int = 0 + let k: Int = 0 + while k < ce_rc { + let rn: String = manifold_rel_name(m, k) + if str_eq(rn, "sounds_before") { + let w: Float = manifold_rel_weight(m, k) + let dw: Float = w - 0.8 + if dw < 0.001 { if dw > -0.001 { found_w = found_w + 1 } } + } + k = k + 1 + } + assert found_w == 1, "the ordering relation carries the weight its realizer stated" + + let fm: Int = manifold_free(m) +} + +test "distinct-signals-decompose-differently" { + let reg: Int = realizer_register("tone", "tone_realizer") + let m2: Manifold = transduce("CE", "tone") + let m3: Manifold = transduce("CEG", "tone") + let two_sz: Int = manifold_size(m2) + let three_sz: Int = manifold_size(m3) + assert two_sz == 3, "two notes decompose into two notes and one interval" + assert three_sz == 5, "three notes decompose into three notes and two intervals" + // Structure differs, not just position: fingerprints of a two-note and a + // three-note signal have identical shape and differ only numerically. + let two_rc: Int = manifold_rel_count(m2) + let three_rc: Int = manifold_rel_count(m3) + assert two_rc < three_rc, "and the relational structure itself differs" + let f2: Int = manifold_free(m2) + let f3: Int = manifold_free(m3) +} + +test "the-registry-keys-on-modality" { + let r1: Int = realizer_register("tone", "tone_realizer") + let rp: Int = realizer_register("pulse", "pulse_realizer") + assert rp > 0, "a second modality registers independently" + let mt: Manifold = transduce("CEG", "tone") + let mp: Manifold = transduce("CEG", "pulse") + let tone_sz: Int = manifold_size(mt) + let pulse_sz: Int = manifold_size(mp) + assert tone_sz == 5, "tone still routes to its own realizer" + assert pulse_sz == 2, "pulse routes to a different realizer, with its own decomposition" + let onset: Int = manifold_index_of(mp, "onset") + assert onset > -1, "and to that realizer's own component vocabulary" + let f1: Int = manifold_free(mt) + let f2: Int = manifold_free(mp) +} + +test "no-organ-is-reported-as-no-organ" { + // A modality with no realizer must transduce to NOTHING. It must never + // fall back to embedding a description of the signal and calling that + // perception — that silent substitution is the original defect. + let has: Int = realizer_has("echolocation") + assert has < 1, "unregistered modality has no organ" + let m: Manifold = transduce("anything", "echolocation") + let live: Int = manifold_is(m) + assert live < 1, "no realizer means no manifold, not a fake one" +} + +test "registration-of-an-unresolvable-name-fails-loudly" { + let bad: Int = realizer_register("ghost", "no_such_function_anywhere") + assert bad < 1, "an unresolvable realizer name is a registration failure" + let has: Int = realizer_has("ghost") + assert has < 1, "and nothing gets registered" +} + +test "a-fingerprint-realizer-transduces-nothing" { + // THE SUPERSESSION OF #144, asserted directly. fingerprint_realizer is + // exactly what the merged primitive asked a realizer to be: signal in, one + // Geometry out. It resolves, so registration succeeds — the organ is + // present. But it does not decompose, so it does not transduce. + // + // This is a deliberate hard failure. "No organ" and "an organ that only + // fingerprints" must not be indistinguishable, which is the same + // distinction realizer_register already draws between an absent and a + // broken organ. A modality with genuinely one part says so with + // manifold_single, and is then visibly a size-1 manifold. + let reg: Int = realizer_register("fingerprint", "fingerprint_realizer") + assert reg > 0, "the symbol resolves, so registration succeeds" + let m: Manifold = transduce("x", "fingerprint") + let live: Int = manifold_is(m) + assert live < 1, "a single vector is not a transduction" +} + +test "a-realizer-returning-nonsense-transduces-nothing" { + let reg: Int = realizer_register("bogus", "bogus_realizer") + assert reg > 0, "the symbol resolves, so registration succeeds" + let m: Manifold = transduce("x", "bogus") + let live: Int = manifold_is(m) + assert live < 1, "a non-Manifold return transduced nothing" +} + +test "the-one-part-case-is-a-size-one-manifold-not-a-bare-vector" { + // Some modalities really do have one part. That is a manifold of size 1 — + // a special case of decomposition, not a parallel path back to a + // fingerprint. Anything reading it still asks manifold_size and still gets + // a real answer, and a second part can be added later without changing the + // type of the thing. + let g: Geometry = geometry_new(3) + let s: Int = geometry_set(g, 0, 5.0) + let m: Manifold = manifold_single("level", "scalar", g) + let live: Int = manifold_is(m) + assert live > 0, "manifold_single yields a real Manifold" + let one_sz: Int = manifold_size(m) + assert one_sz == 1, "of size one — visibly degenerate, not hidden" + let idx: Int = manifold_index_of(m, "level") + assert idx == 0, "and its one part is still addressable by name" + let f: Int = geometry_free(g) + let fm: Int = manifold_free(m) +}