runtime: transduction decomposes a signal into components and relations, it does not convert it to a point #155
Reference in New Issue
Block a user
Delete Branch "fix/transduce-decomposition"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The premise that was wrong
Transduction is not conversion. #144 implemented it as signal → one vector: take a thing, encode it, store a position. That is a fingerprint, not a transduction. 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 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 — components, each with its own geometry, plus the relations between them. The song is the structure of the relations.
transduce(signal, modality)now returns a Manifold: named components carrying geometry, and typed weighted relations among them. Signal in, subgraph out.Judgement on the
transduce_manifoldinversionThe inversion is real, and the rename enshrined it — but neither layer was doing transduction. Evidence:
transduce(#144,el_runtime.c)ElGeometry { int32_t dim; float* v; }— a flat vector,geometry_get/set(i),geometry_norm,to_f32le_hex.el_realizer_fnisel_val_t (*)(el_val_t): one value in, one opaque value out. No components. No edges.transduce_manifold(ingest.el)contains,precedes,section_of) — a subgraphSo the rename moved the name from the layer with the right output shape to the layer with the wrong output type. That is the bug, exactly as reported.
The correction to the report:
transduce_manifoldwas not simply right. It decomposes by byte boundary —str_split(source, "\n\n"), else fixed 4096-byte windows — and declares "zero semantic understanding of any payload." Its components are positional, not meaningful. Splitting a WAV into 4096-byte windows is not pitch/interval/rhythm. So it is transduction in shape and a modality-blind degenerate case in content.The real fix therefore is not to swap the names back. It is to give the primitive the subgraph return type, at which point both layers are doing the same kind of operation and the inversion dissolves rather than needing to be re-argued. What remains is a genuine distinction about modality, not layering — so
transduce_manifoldis renamedtransduce_bytes(suffixed by its modality, not demoted by layer), and the comment block that recorded the inverted reasoning is replaced with this account.The decomposing realizer contract
Design decisions, each load-bearing:
correspondence-and-censorship.md§1). A realizer states a relation and the weight is the claim; nothing computes or observes a grounding (§4).manifold_addcopies,manifold_geometryreturns a copy. No component's vector is aliased in either direction.manifold_single— a size-1 manifold, visibly degenerate, not a parallel path back to a bare vector.Evidence, with negative controls
Baseline:
test_transduce.elon pristineorigin/dev(385c184) →12 tests, 12 passed. The baseline was green, so these controls are not measuring a pre-broken tree.Positive:
25 tests, 25 passed, 83 assertions. Worked examplelang/examples/transduce.elexits 0.Control A — the unpatched build cannot express the contract. The same test file, compiled by the same
elcagainst pristineorigin/dev: El → C succeeds, thenccfails withcall to undeclared function 'manifold_new' / 'manifold_add' / 'manifold_index_of' / 'manifold_relate' / …. No binary is produced.Control B — same signal, same engram, both builds, measured.
"CEG"transduced and persisted (in-memory engram; no server contacted):-> Geometry)-> Manifold)Read back from the graph on the patched build,
note:0carries{"relation":"corroborates","weight":0.95}from its evidence node, and that edge is demonstrably absent fromnote:2— one part grounded, the sibling untouched, with both geometries intact. On the unpatched build both the corroboration and the contradiction land on one undifferentiated point.A defect found while proving this — NOT fixed here
The contradiction half of the demonstration does not work, and not because of decomposition.
engram_connectatel_runtime.c:9730:A weight of
-0.85is silently coerced to0.5. A stated contradiction is stored as moderate support, withinhibitory: 0. Verified by read-back, not inferred.This is precisely the polarity gap named in
correspondence-and-censorship.md§2 — "negative means this actively contradicts…inhibitoryis that distinction crushed to one bit." It is a separate defect from the one this PR fixes. Decomposition is the precondition for contradicting one part while a sibling holds, and it now exists; a signed edge weight is what is still missing.What #141 and #144 become
engram_node_set_emb(id, hex, dim)— UNCHANGED, still wire-compatible. It was already superseded in place on 2026-08-16 and reimplemented asgeometry_from_f32le_hex+node_attach_geometry. This PR does not touch it, and the"emb"hex wire format on/api/nodesis untouched. Production clients speaking hex keep working.transduce -> Geometry— SUPERSEDED, deliberately breaking. A realizer still returning a bareGeometrynow transduces nothing (transducereturns 0). This is a hard failure by design: "no organ" and "an organ that only fingerprints" must not be indistinguishable — the same distinctionrealizer_registeralready draws between an absent and a broken organ. Asserted directly by the testa-fingerprint-realizer-transduces-nothing.realizer_register/realizer_has/ dlsym-by-name — UNCHANGED and vindicated. The dispatch design was right; only the return type was wrong.Geometry— UNCHANGED, and relocated in meaning. Every #141/#144 geometry test still passes verbatim. A vector was never wrong; it was misplaced. It is the right representation for a component, and was only ever wrong as the representation of a whole signal.What I did NOT get to
transduce_bytesis still not a registered realizer. It should return a realManifoldand ride the primitive like every other modality, instead of carrying a parallel node+edge implementation against the HTTP API. Renamed and documented, not converted.:9730clamp above) — diagnosed, not fixed./api/nodes/embread-back route onfeat/love-originis untouched and unmerged.server.eluntouched. Nothing in the HTTP surface exposes a Manifold yet; a transduced subgraph currently reaches the graph only through in-process El./api/search — characterised, and the reported symptom is wrong
Investigated on an isolated APFS clone (
cp -Rc) served on port 8911 with PID/port ownership verified againstlsof. Prod:8742and soul:7770were never touched.It does not return the same cluster for every query. Across 17 queries the union was 102 distinct ids and the intersection was 0. Two distinct behaviours: unmatched queries (
zzzznonsense,photosynthesis) return 0 results, not a cluster; matched queries often collapse onto the Working-tier skill-curriculum cluster while discarding the query's own exact-label node./api/search-lexicalis correct throughout — the lexical path is fine, the geometric gate is the defect.Root cause in
engram_retrieve_geometric_json,lang/runtime/el_runtime.c(line numbers against385c184)::13622-13625— dominant. The region tag is applied as a hard filter, not a rank boost:if(!keep) continue;. The correct exact-label node is seeded and activated, then discarded for lacking the addressed tag. Only ~38 skill-curriculum nodes carry tags, so the answer collapses onto them.:13575-13581— the coarse gate has no concentration threshold (unlike the fine branch at:13570), and truncating at the first:makesdom_familyalways literally"skill:"— it cannot tellskill:programmingfromskill:arithmetic.:13533+:9288-9300—engram_node_match_scoreis case-insensitive substring match with no stopwords and no word boundaries, so"self"matches "give every number times itself". Almost any common word seeds a tagged node and trips the gate.:13626—hits[nh].score=0is hard-coded whileengram_rank_cmpsorts on score first, so lexical evidence is discarded from ranking (compareengram_search_json:13435, which setsscore = sccorrectly).Not fixed here; out of scope for this PR.
Build
The committed CI recipe does not link on macOS.
-lssl -lcryptoare unresolvable, andel_runtime.calone leaves ~60 undefined symbols —el_seed.c(ownsel_request_end) and the sixengram_*.cunits are required.No process was deployed, restarted, or signalled. Prod engram
:8742and soul:7770were untouched throughout.c82a4d2f90to688f24b4c1