Compare commits

..

9 Commits

Author SHA1 Message Date
Neuron 688f24b4c1 ingest: name the inversion, and correct the worked example to decomposition
El SDK CI - dev / build-and-test (pull_request) Failing after 14m6s
ingest.el's transduce() was renamed to transduce_manifold() earlier the same
day on the reasoning that it 'was never signal->geometry -- it chunks
already-extracted content and PACKS it into a node+edge manifold, one layer up,
and it had taken the name that belongs to the primitive underneath it.'

That reasoning was backwards. Producing a node+edge manifold is not a layer
above transduction, it IS transduction. Signal -> one vector is the operation
underneath, and its name is geometry. The layer doing it right was renamed out
of the way so the layer doing it wrong could have the name.

With the primitive corrected to return a Manifold, the two layers do the same
kind of thing and the inversion dissolves. What is left is a real distinction
about MODALITY, not layering: transduce() dispatches to a realizer that knows
its modality and can name its components; transduce_bytes() is the
opaque-bytes realizer, the decomposition available to a reader that knows
nothing about what it is reading. It still yields components and relations,
which is why it is transduction and not packing -- it just cuts on byte
boundaries, so its components are positional rather than meaningful. That is a
limitation of this realizer, not the definition of the operation.

Renamed by modality rather than demoted by layer. A distinct symbol is still
mechanically required: reusing transduce here is a conflicting-types error the
moment ingest.c links el_runtime.c.

lang/examples/transduce.el asserted #144's contract and would now fail, so it
is replaced by the decomposition worked example: transduce a chord, persist the
five components and six relations as real nodes and edges, read each part's
geometry back off its own node, and ground one part while its sibling is
demonstrably untouched.
2026-08-16 15:50:00 -05:00
Neuron d777936ee4 runtime: transduction decomposes a signal, it does not convert it
#144 moved transduction into the language and got the dispatch right. It got
the result type wrong: transduce(signal, modality) -> Geometry yields one
vector per signal, and one vector is a fingerprint. A fingerprint can be
matched and ranked; that is all. 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 among
them. The song IS the structure of the relations.

transduce now returns a Manifold: named components carrying geometry, and
typed weighted relations between them. Signal in, subgraph out.

Components are addressed by key, never by index, because the key is what
survives persistence -- a component becomes a node and is separately groundable
precisely because it is separately named. Relation weight IS the grounding
(correspondence-and-censorship.md 1), so a realizer's relations arrive already
grounded and there is no score computed beside them.
2026-08-16 15:50:00 -05:00
will.anderson 4a57b4faa8 Merge pull request 'docs: the builtin recipe never required a test' (#154) from docs/builtin-recipe-gate into dev
El SDK CI - dev / build-and-test (push) Failing after 3m53s
2026-08-16 20:49:21 +00:00
will.anderson 0ee82d9e91 Merge pull request 'Grounding is the edge's weight, and the weight is a vector' (#150) from feat/grounding-gradient into dev
El SDK CI - dev / build-and-test (push) Failing after 3m43s
2026-08-16 20:49:12 +00:00
will.anderson 9526bda507 Merge pull request 'engram: expose the geometry so the frame can be verified' (#156) from fix/geometry-readable into dev
El SDK CI - dev / build-and-test (push) Failing after 4m7s
2026-08-16 20:49:07 +00:00
Neuron 0389bf9363 engram: expose the geometry so the frame can be verified
El SDK CI - dev / build-and-test (pull_request) Failing after 11m29s
engram_scan_nodes_emb_json has existed as a builtin with NO ROUTE. The
embeddings — the actual positions every distance, angle, membership and
grounding is computed from — were unreadable from outside the process.

That is not a missing convenience. It means every claim about the
coordinate frame was unfalsifiable from the API: whether the space is
isotropic, where the centering offset sits, what the origin is, whether a
node carries geometry at all. You cannot verify a coordinate system you
cannot see, and a system whose frame cannot be checked is exactly the
shape this codebase spent 2026-08-16 removing everywhere else.

GET /api/nodes/emb?limit=&offset=. Read-only, paged, no writes.

Measured consequence of having it: the value manifold and the love
component manifold were both decomposed, null-controlled against random
node sets drawn from the same graph, and several published claims were
retracted because the geometry contradicted them. None of that was
possible before this route existed.
2026-08-16 15:37:22 -05:00
Neuron fe820928b0 docs: the builtin recipe never required a test
El SDK CI - dev / build-and-test (pull_request) Failing after 10m55s
lang/AGENTS.md:71-77 gives four steps for adding a C builtin and ends at
'confirm the self-host fixpoint is byte-identical'. No step asks for a test.
The only 'verify' in the file is that fixpoint, which proves the COMPILER
REPRODUCES ITSELF and says nothing about whether the builtin works — so the
recipe reads as complete while having checked nothing about the thing just
added.

Measured on 2026-08-16: engram_node_set_emb, engram_curiosity_json and
dream_set_handler were all added in a single session with zero tests, by an
agent following this recipe. Separately a UTF-8 fix was written and tested
and THE TEST PASSED ON THE UNPATCHED BUILD — the real defect was elsewhere,
and only building the pre-fix binary exposed it. Without a negative control
that fix would have merged as verified.

Adds step 5 with the two failure shapes actually encountered: a test that
never exercises the change (a route default bypassed the code under test),
and an induction that loses a race (curl --max-time left BOTH builds alive;
only SO_LINGER 0, a real RST, reproduced it). Plus the port-binding check,
because a stale instance answering has silently produced false results here
more than once and pkill -f does not reliably match argv './engram'.

Documentation only. Does not touch the (a) split-the-C / (b) close-the-
compiler-gap question, which is a separate decision.
2026-08-16 13:53:08 -05:00
will.anderson 385c18442d runtime: a disconnecting client must not kill the server (#151)
El SDK CI - dev / build-and-test (push) Failing after 3m53s
2026-08-16 18:33:50 +00:00
Neuron cace6a5ebf runtime: a disconnecting client must not kill the server
El SDK CI - dev / build-and-test (pull_request) Failing after 13m45s
There was no SIGPIPE handling anywhere in this runtime: no signal
disposition, no MSG_NOSIGNAL, no SO_NOSIGPIPE, and send() called with bare
flags. The default disposition of SIGPIPE is to TERMINATE THE PROCESS, so
any client that hangs up mid-response takes the whole engram with it.

MEASURED, and it is not hypothetical. Production has restarted 254 times
since 2026-08-13T19:37 at a flat ~10 minute cadence:

  17:05:18  17:15:29  17:25:38  17:35:50  17:46:00  17:56:10  18:06:22  18:16:30

Intervals of 10m09s-10m12s, not 10m00s. That excess is the whole story:
ai.neuron.engram-tick has StartInterval 600, and engram-tick.sh:13 calls

  curl -s -m10 -X POST .../api/tick

The beat does not finish within 10s over 13,634 nodes, so curl waits its
full timeout and closes. The engram then writes the tick response to a dead
socket, takes SIGPIPE, and dies. launchd KeepAlive restarts it, so the
failure presents as a mysterious restart rather than a crash — and
~/.neuron/logs/engram.log records nothing but "[http] listening on" 254
times, with no exit reason. launchctl list confirms the last exit as -13.

Root cause is one level out: consolidation had no owner, so an external
ticker was created to poke it, and the ticker is what kills it. The fix
here does not address that; it makes the process survivable while it is
addressed.

Two layers, because neither alone is portable:
  - SO_NOSIGPIPE per accepted socket (Darwin/BSD) and MSG_NOSIGNAL per send
    (Linux), so the signal is never raised for socket writes at all.
  - A process-wide SIG_IGN backstop, installed once and idempotent, for
    platforms and paths with neither. With the signal ignored, send()
    returns -1/EPIPE and the existing error path closes the connection.

Also retries send() on EINTR, which the previous loop treated as fatal.

This is an exemption in the sense of lang/spec §8: the write never checked
whether the peer was still there, and the consequence of not checking was
fatal rather than merely wrong.
2026-08-16 13:25:14 -05:00
7 changed files with 1161 additions and 366 deletions
+19
View File
@@ -1025,6 +1025,22 @@ fn route_similarity(method: String, path: String, body: String) -> String {
// nothing on request. NOTE: the offline reify WRITER (engram_geo_reify_store) is
// currently unwired, so on the live store the resident index is empty and the
// list returns [] until reification runs see the cutover report.
// route_scan_emb GET /api/nodes/emb?limit=&offset= read the raw geometry.
//
// engram_scan_nodes_emb_json has existed as a builtin with NO ROUTE, so the
// embeddings the actual positions every distance, angle, membership and
// grounding is computed from were unreadable from outside the process. You
// cannot verify a coordinate system you cannot see, and every claim about the
// frame (isotropy, centering, what the origin is) was therefore unfalsifiable
// from the API. Read-only.
fn route_scan_emb(method: String, path: String, body: String) -> String {
let l_raw: String = query_param(path, "limit")
let o_raw: String = query_param(path, "offset")
let l: Int = if str_eq(l_raw, "") { 200 } else { str_to_int(l_raw) }
let o: Int = if str_eq(o_raw, "") { 0 } else { str_to_int(o_raw) }
return engram_scan_nodes_emb_json(l, o)
}
fn route_neighborhoods(method: String, path: String, body: String) -> String {
engram_geo_reify_list_json()
}
@@ -1820,6 +1836,9 @@ fn handle_request(method: String, path: String, body: String) -> String {
if str_eq(method, "GET") && (str_eq(clean, "/api/edges") || str_eq(clean, "/edges")) {
return route_scan_edges(method, path, body)
}
if str_eq(method, "GET") && (str_eq(clean, "/api/nodes/emb") || str_eq(clean, "/nodes/emb")) {
return route_scan_emb(method, path, body)
}
if str_eq(method, "GET") && str_starts_with(clean, "/api/nodes/") {
return route_get_node(method, path, body)
}
+54 -25
View File
@@ -13,7 +13,7 @@
// relations add edges. Every node enters with PROVENANCE + grounding-level
// + stewardship class from the moment of entry.
//
// transduce_manifold() is THE single mechanism one function, polymorphic, with no
// transduce_bytes() is THE single mechanism one function, polymorphic, with no
// content-type branch inside it. It does not ask whether a payload is
// prose, structured data, or raw/opaque bytes (audio, or anything else);
// it runs one boundary-scan-with-fixed-window-fallback chunking algorithm
@@ -401,25 +401,54 @@ fn head80(s: String) -> String {
// truncates at the first embedded NUL, which is routine in real binary
// bytes) is a MECHANICAL fidelity concern that belongs to whatever produced
// `source` (see ingest_file's file_source_string below) not a
// content-type judgment made in here. transduce_manifold() never learns whether a
// content-type judgment made in here. transduce_bytes() never learns whether a
// chunk is plain text or a base64-encoded raw-byte window; every chunk is
// handled identically either way.
// RENAMED transduce -> transduce_manifold (2026-08-16). Two reasons, and the
// first is not the interesting one:
// NAMING, CORRECTED 2026-08-16 (second pass). This function was renamed
// `transduce` -> `transduce_bytes` earlier the same day, on the reasoning
// that it "was never signal->geometry — it chunks already-extracted content
// and PACKS it into a node+edge manifold, one layer up, and it had taken the
// name that belongs to the primitive underneath it."
//
// 1. Mechanical: `transduce` is now a LANGUAGE primitive in el_runtime.h
// (transduce(signal, modality) -> Geometry). Every El `fn name(...)`
// compiles to a global C symbol with that exact name, so keeping this
// name here is a hard `conflicting types for 'transduce'` compile error
// the moment ingest.c links el_runtime.c. Measured, not anticipated.
// THAT REASONING WAS BACKWARDS, and it is worth recording why rather than
// quietly re-renaming. Producing a node+edge manifold is not a layer above
// transduction it IS transduction. Transduction is not conversion. When you
// take in music you do not store the song as one discrete geometry; you break
// it into its component parts and store the geometry of each along with the
// relations between them. The song is the structure of those relations.
// Signal -> one vector is the operation UNDERNEATH transduction, and its name
// is encoding, or geometry. So the layer that was doing it right got renamed
// out of the way so the layer doing it wrong could have the name.
//
// 2. Actual: this function was never signal->geometry. It chunks already-
// extracted content and PACKS it into a node+edge manifold a real
// operation, but one layer up, and it had taken the name that belongs to
// the primitive underneath it. `transduce` is where a signal becomes
// geometry; `transduce_manifold` is where extracted content becomes
// structure. Nothing about this function's behaviour changed.
fn transduce_manifold(nodes: [String], edges: [String], source: String,
// The primitive has since been corrected: `transduce(signal, modality)` now
// returns a Manifold components plus relations not a Geometry
// (el_runtime.c, "Manifold"). The two layers are therefore doing the SAME KIND
// of thing, and the inversion dissolves rather than needing to be re-argued.
//
// What is left is a real distinction, and it is about MODALITY, not layering:
//
// * `transduce(signal, modality)` dispatches to a realizer that KNOWS the
// modality and can name its components for audio: pitch, interval,
// rhythm, harmonic function.
// * `transduce_bytes` below is the OPAQUE-BYTES realizer: the decomposition
// available to a reader that knows nothing about what it is reading. It
// still yields components and relations (chunk nodes; contains / precedes
// / section_of edges), which is why it is transduction and not packing. It
// just cuts on the only structure visible without understanding byte
// boundaries so its components are positional rather than meaningful.
// That is a LIMITATION of this realizer, not the definition of the
// operation.
//
// The name is suffixed by its modality, not demoted to a lesser layer. Keeping
// a distinct symbol is also still mechanically required: every El `fn name`
// compiles to a global C symbol, so reusing `transduce` here is a hard
// `conflicting types` error the moment ingest.c links el_runtime.c.
//
// WHERE THIS SHOULD GO: this function should become a registered realizer
// returning a real Manifold, so ingest rides the same primitive as every other
// modality instead of carrying a parallel implementation. Not done here.
// Nothing about this function's behaviour changed in this pass.
fn transduce_bytes(nodes: [String], edges: [String], source: String,
prov: String, ground: String, steward: String,
root_lid: String, root_title: String) -> [String] {
let tagbase: String = "prov:" + prov + " ground:" + ground + " steward:" + steward
@@ -546,8 +575,8 @@ fn default_steward() -> String {
// trustworthy verbatim. When they don't (silent truncation happened),
// rebuild the payload as base64-encoded fixed-size windows read directly
// off disk (fs_read_b64_chunk binary-safe in C), joined with the same
// "\n\n" boundary marker transduce_manifold()'s generic scan already looks for, so
// transduce_manifold() sees one ordinary boundary-delimited payload and runs its one
// "\n\n" boundary marker transduce_bytes()'s generic scan already looks for, so
// transduce_bytes() sees one ordinary boundary-delimited payload and runs its one
// algorithm on it exactly as it would on prose it never learns that a
// fidelity problem occurred upstream, let alone why.
fn file_source_string(path: String, text: String, real_size: Int) -> String {
@@ -556,7 +585,7 @@ fn file_source_string(path: String, text: String, real_size: Int) -> String {
// 3072 raw bytes -> 4096 base64 chars (3 divides evenly into base64's
// 3-byte/4-char ratio); keeps each resulting node's content a clean,
// bounded, low-kilobytes unit, same order of magnitude as the fixed
// fallback window in transduce_manifold() itself.
// fallback window in transduce_bytes() itself.
let win: Int = 3072
let out: String = ""
let off: Int = 0
@@ -576,7 +605,7 @@ fn file_source_string(path: String, text: String, real_size: Int) -> String {
}
// ingest one file -> report JSON. Uniform for every file regardless of
// extension or content transduce_manifold() decides nothing about content-type, so
// extension or content transduce_bytes() decides nothing about content-type, so
// neither does this function; it only decides whether the raw bytes made it
// through the read intact (file_source_string), which is a fidelity
// question, not a format one.
@@ -588,14 +617,14 @@ fn ingest_file(path: String) -> String {
return "{\"error\":\"empty or unreadable\",\"path\":" + j_q(path) + "}"
}
let prov: String = "file:" + path
let packed: [String] = transduce_manifold(el_list_empty(), el_list_empty(),
let packed: [String] = transduce_bytes(el_list_empty(), el_list_empty(),
source, prov, default_ground(), default_steward(),
"doc:" + basename(path), basename(path))
return merge_packed(packed)
}
// ingest a directory: walk one level, ingest every file found, aggregate.
// No extension filter transduce_manifold() handles any payload uniformly now, so
// No extension filter transduce_bytes() handles any payload uniformly now, so
// there is no content-type gate at the directory boundary either.
fn ingest_dir(path: String) -> String {
let entries: [String] = fs_list(path)
@@ -630,7 +659,7 @@ fn ingest_dir(path: String) -> String {
fn ingest_url(url: String) -> String {
let body: String = http_get(url)
if str_eq(body, "") { return "{\"error\":\"empty fetch\",\"url\":" + j_q(url) + "}" }
let packed: [String] = transduce_manifold(el_list_empty(), el_list_empty(),
let packed: [String] = transduce_bytes(el_list_empty(), el_list_empty(),
body, "url:" + url, "extracted", "public-web",
"url:" + url, url)
return merge_packed(packed)
@@ -645,7 +674,7 @@ fn ingest_llm(query: String) -> String {
let resp: String = http_post_json("http://127.0.0.1:11434/api/generate", body)
let answer: String = json_get_string(resp, "response")
if str_eq(answer, "") { return "{\"error\":\"no model response\"}" }
let packed: [String] = transduce_manifold(el_list_empty(), el_list_empty(),
let packed: [String] = transduce_bytes(el_list_empty(), el_list_empty(),
answer, "llm:" + model + ":" + query, "candidate-provisional", "guide-provisional",
"llm:" + query, "guide answer: " + query)
return merge_packed(packed)
@@ -697,7 +726,7 @@ fn ingest_stream(path: String) -> String {
// It is NOT a content-type flag: it says nothing about what's inside the
// bytes once fetched, and none of the five ingest_* functions it selects
// among interpret their payload differently by content shape anymore
// they all hand off to the single, format-agnostic transduce_manifold(). The old
// they all hand off to the single, format-agnostic transduce_bytes(). The old
// "structured" value (a caller-declared alias for "file", used only to hint
// the now-removed JSON-vs-prose branch) is gone along with that branch.
let kind: String = env("INGEST_KIND")
+11
View File
@@ -73,6 +73,17 @@ When you add a C builtin (verbatim-emit recipe — the El name is emitted as the
2. Add a `__`-prefixed thin wrapper in `el_seed.c` and declare it in `el_seed.h`.
3. Add the name to `builtin_arity` in `el-compiler/src/codegen.el` — add **both** the plain and `__`-prefixed spellings.
4. Rebuild the elc binary (see below) and confirm the self-host fixpoint is byte-identical.
5. **Prove it with a NEGATIVE CONTROL.** Show the test FAILING on a build without your change, then passing with it. A test that has never been seen to fail has proven nothing.
> **Step 5 is not optional, and step 4 does not cover it.** The fixpoint proves the *compiler reproduces itself*. It says nothing whatsoever about whether your builtin works. A recipe ending at "byte-identical" reads as complete while having verified nothing about the thing just added — which is why this file, until 2026-08-16, produced builtins with no tests at all.
>
> Measured cost of the omission (2026-08-16): `engram_node_set_emb`, `engram_curiosity_json` and `dream_set_handler` were all added in one session with zero tests. Separately, a UTF-8 fix was written, tested, and **the test passed on the unpatched build too** — the defect was elsewhere entirely, and only building the pre-fix binary exposed it. Without a negative control that fix would have merged as verified.
>
> Two shapes that pass while proving nothing, both hit the same day:
> - A test that never exercises your change (the route supplied a default that bypassed the code under test).
> - An induction that loses a race. `curl --max-time` on a large response left *both* builds alive; only `SO_LINGER 0` — a genuine RST, so the peer is provably gone — reproduced the failure. Six of ten attempts is not a control.
>
> Before every probe, confirm **your** process bound the port (`lsof -nP -iTCP:<port>`, match the PID). A stale instance answering on the port has silently produced false results here more than once, and `pkill -f` does not reliably match an argv like `./engram`.
Worked example: the `engram_assert_json` (op_assert seam) and `engram_node_full_in`/`engram_connect_in` (purview write-side) primitives added 2026-08-15 follow exactly this recipe.
+183 -168
View File
@@ -1,67 +1,33 @@
// transduce.el geometry as a first-class El value, and a realizer written
// in El. Runnable: this is the worked example for the transduce surface, and
// it doubles as an executable proof because it checks every claim it makes.
// transduce.el transduction decomposes a signal into components and the
// relations between them. Runnable: this is the worked example for the
// transduce surface, and it exits non-zero if any claim in it stops being true.
//
// elc lang/examples/transduce.el > transduce.c
// cc -std=c11 -O2 -I lang/runtime -o transduce transduce.c \
// lang/runtime/el_runtime.c lang/runtime/el_seed.c \
// lang/runtime/engram_*.c -lcurl -lpthread -lm
// lang/runtime/el_runtime.c lang/runtime/el_seed.c \
// lang/runtime/engram_store.c lang/runtime/engram_vindex.c \
// lang/runtime/engram_cognition.c lang/runtime/engram_geometry.c \
// lang/runtime/engram_reason.c lang/runtime/engram_verify.c \
// -lcurl -lpthread -lm
// ./transduce # exits 0 only if every check passes
//
// (A `test "..."` form of the same checks lives in
// lang/tests/native/test_transduce.el, for when the native harness is
// repaired the shipped elc currently emits calls to __el_reg_count and
// friends without emitting their definitions, which breaks every native test
// equally, test_math.el included. Verified 2026-08-16, unrelated to this work.)
// It writes to an IN-MEMORY engram (leave ENGRAM_STORE unset) and contacts no
// server. The same claims are asserted by the native harness in
// lang/tests/native/test_transduce.el.
//
// WHY THIS EXISTS. Until 2026-08-16 no El ingest path could carry a vector:
// nodes took text, and geometry was DERIVED from that text. Text was 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. Two things fix that, and both are shown
// below: geometry is a VALUE that carries its own width, and a REALIZER is an
// ordinary El function so admitting a new modality never requires a runtime
// patch.
// WHAT CHANGED, AND WHY IT MATTERS. #144 shipped
// `transduce(signal, modality) -> Geometry`: one vector per signal. That made
// transduction a CONVERSION take a thing, encode it, store a position and
// what a conversion returns is a fingerprint. A fingerprint can be matched and
// ranked, and that is all 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.
//
// COMPARISON DISCIPLINE (measured, not stylistic): elc lowers `a == b`
// numerically only when both operand NAMES are in the per-function int-name
// set that `let x: Int` populates. A bare `f(x) == 0` is not a registered
// name and lowers to str_eq strcmp on two integers as pointers. `<` and `>`
// lower directly with no inference, so truthiness is written `> 0` / `< 1`.
// 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. transduce now returns a
// Manifold, and a realizer's job is to say what its modality's components ARE.
// A realizer, written entirely in El
// Not in the runtime. Not known to the compiler. Registered by NAME and
// dispatched to through transduce(). That is the whole claim.
fn tone_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 modality, to show the registry keys on modality rather than just
// returning whatever was registered last.
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: returns something that is not a Geometry.
fn bogus_realizer(signal: String) -> Geometry {
return 12345
}
// Fails FAST rather than accumulating a count, for a measured reason: a first
// cut wrote `let fails: Int = fails + check(...)` and `+` lowered to STRING
// CONCAT, because elc dispatches `+` on whether both operands are known-Int and
// a user-defined fn call is not so the counter printed 4343632752, a pointer.
// Nothing was wrong with the checks; the tally was lying. Exiting at the first
// failure needs no arithmetic at all, so there is nothing left to get wrong.
fn check(ok: Int, label: String) -> Int {
if ok > 0 {
println(" ok " + label)
@@ -84,128 +50,177 @@ fn eq_int(a: Int, b: Int) -> Int {
return 0
}
// A DECOMPOSING realizer, written entirely in El
// "tone" signals are note letters, e.g. "CEG". This 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 a field on a note. An interval
// is a thing with its own geometry belonging to neither endpoint; modelling it
// as an attribute of one of them is the same collapse, 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
}
// #144's contract, kept as a control: one vector for the whole signal.
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))
g
}
fn main() -> Void {
println("geometry is a value that carries its own width")
let g8: Geometry = geometry_new(8)
let _c: Int = check(geometry_is(g8), "geometry_new returns a live Geometry")
let d8: Int = geometry_dim(g8)
let _c: Int = check(eq_int(d8, 8), "a Geometry carries its own width (8)")
let _c: Int = check(geometry_free(g8), "geometry_free reports what it did")
println("nonsense is refused — with no arbitrary max-dim bound")
// #141 needed `dim <= 8192` only to bound an allocation sized from a
// caller's CLAIM about a string's length. A value that carries its own
// width has nothing left to validate.
let z: Geometry = geometry_new(0)
let zi: Int = geometry_is(z)
let _c: Int = check(1 - zi, "dim 0 is not a geometry")
let ng: Geometry = geometry_new(-4)
let ngi: Int = geometry_is(ng)
let _c: Int = check(1 - ngi, "negative dim is not a geometry")
let nd: Int = geometry_dim(0)
let _c: Int = check(1 - nd, "geometry_dim of a non-geometry is 0, not a crash")
let nf: Int = geometry_free(0)
let _c: Int = check(1 - nf, "geometry_free of a non-geometry is a no-op")
println("components round-trip, and out-of-range is refused")
let g3: Geometry = geometry_new(3)
let s0: Int = geometry_set(g3, 0, 1.5)
let s1: Int = geometry_set(g3, 1, -2.5)
let _c: Int = check(s0, "set in range succeeds")
let oob: Int = geometry_set(g3, 3, 9.0)
let _c: Int = check(1 - oob, "set out of range is refused, not silently dropped")
let _c: Int = check(near(geometry_get(g3, 0), 1.5), "component 0 round-trips")
let _c: Int = check(near(geometry_get(g3, 1), -2.5), "component 1 round-trips (negative)")
let ff3: Int = geometry_free(g3)
println("hex is an EDGE adapter, and derives its own width")
// little-endian float32: 1.0 = 0000803f, 2.0 = 00000040
let gh: Geometry = geometry_from_f32le_hex("0000803f00000040")
let _c: Int = check(geometry_is(gh), "valid hex decodes to a Geometry")
let dh: Int = geometry_dim(gh)
let _c: Int = check(eq_int(dh, 2), "width DERIVED from input, never supplied")
let _c: Int = check(near(geometry_get(gh, 0), 1.0), "first component decoded")
let _c: Int = check(near(geometry_get(gh, 1), 2.0), "second component decoded")
let back: String = geometry_to_f32le_hex(gh)
let _c: Int = check(str_eq(back, "0000803f00000040"), "hex round-trips exactly")
let ffh: Int = geometry_free(gh)
println("malformed hex is refused")
let he: Geometry = geometry_from_f32le_hex("")
let hei: Int = geometry_is(he)
let _c: Int = check(1 - hei, "empty hex is not a geometry")
let hr: Geometry = geometry_from_f32le_hex("0000803f0000")
let hri: Int = geometry_is(hr)
let _c: Int = check(1 - hri, "length not a multiple of 8 is refused")
let hn: Geometry = geometry_from_f32le_hex("zzzzzzzz")
let hni: Int = geometry_is(hn)
let _c: Int = check(1 - hni, "non-hex characters are refused")
println("a realizer declared in El is a first-class realizer")
let reg: Int = realizer_register("tone", "tone_realizer")
let _c: Int = check(reg, "an El fn registers as a realizer BY NAME")
let _c: Int = check(reg, "an El fn registers as a realizer by name")
let _c: Int = check(realizer_has("tone"), "the modality now has an organ")
let gt: Geometry = transduce("aaa", "tone")
let _c: Int = check(geometry_is(gt), "transduce returns real geometry")
let dt: Int = geometry_dim(gt)
let _c: Int = check(eq_int(dt, 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 _c: Int = check(near(geometry_get(gt, 0), 3.0), "the signal REACHED the El realizer")
let fft: Int = geometry_free(gt)
println("distinct signals transduce to distinct geometry")
let g1: Geometry = transduce("aa", "tone")
let g2: Geometry = transduce("aaaaa", "tone")
let a1: Float = geometry_get(g1, 0)
let a2: Float = geometry_get(g2, 0)
// 5 - 2 = 3. If transduction were a stub these would be equal.
let _c: Int = check(near(a2 - a1, 3.0), "different signals produce different geometry")
let ff1: Int = geometry_free(g1)
let ff2: Int = geometry_free(g2)
println("transduction decomposes a signal into parts")
let m: Manifold = transduce("CEG", "tone")
let _c: Int = check(manifold_is(m), "transduce returns a real Manifold")
let sz: Int = manifold_size(m)
let _c: Int = check(eq_int(sz, 5), "three notes and two intervals are five parts")
let rc: Int = manifold_rel_count(m)
let _c: Int = check(eq_int(rc, 6), "and they stand in six stated relations")
println("the registry keys on modality")
let r2: Int = realizer_register("pulse", "pulse_realizer")
let _c: Int = check(r2, "a second modality registers independently")
let mt: Geometry = transduce("aaa", "tone")
let mp: Geometry = transduce("aaa", "pulse")
let mdt: Int = geometry_dim(mt)
let mdp: Int = geometry_dim(mp)
let _c: Int = check(eq_int(mdt, 4), "tone still routes to its own realizer")
let _c: Int = check(eq_int(mdp, 2), "pulse routes to a different realizer")
let ffm1: Int = geometry_free(mt)
let ffm2: Int = geometry_free(mp)
println("every part is addressable BY KEY, which is what survives persistence")
let i_c: Int = manifold_index_of(m, "note:0")
let _c: Int = check(1 - eq_int(i_c, -1), "the first note is addressable on its own")
let i_iv: Int = manifold_index_of(m, "interval:0-1")
let _c: Int = check(1 - eq_int(i_iv, -1), "so is the interval between the first two")
let miss: Int = manifold_index_of(m, "never_added")
let _c: Int = check(eq_int(miss, -1), "an unknown key is -1, not component 0")
println("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 defect this all exists to end.
let eh: Int = realizer_has("echolocation")
let _c: Int = check(1 - eh, "unregistered modality has no organ")
let ge: Geometry = transduce("anything", "echolocation")
let gei: Int = geometry_is(ge)
let _c: Int = check(1 - gei, "no realizer means NO geometry, not fake geometry")
println("parts carry their own geometry, and may differ in width")
let gn: Geometry = manifold_geometry(m, i_c)
let _c: Int = check(eq_int(geometry_dim(gn), 2), "a note component is 2 wide")
let _c: Int = check(near(geometry_get(gn, 0), 67.0), "and it is C — the signal reached the realizer")
let gi: Geometry = manifold_geometry(m, i_iv)
let _c: Int = check(eq_int(geometry_dim(gi), 1), "an interval component is 1 wide")
// A single vector per signal cannot represent parts of unequal width at all.
let _c: Int = check(near(geometry_get(gi, 0), 2.0), "C to E is two semitones")
let f1: Int = geometry_free(gn)
let f2: Int = geometry_free(gi)
println("an unresolvable realizer name fails at WIRING time")
let bad: Int = realizer_register("ghost", "no_such_function_anywhere")
let _c: Int = check(1 - bad, "unresolvable realizer name is a registration failure")
let gh2: Int = realizer_has("ghost")
let _c: Int = check(1 - gh2, "and nothing gets registered")
println("the relations are content no single part carries")
// That "2" above is not a property of C and not a property of E. It exists
// only BETWEEN them, so a representation with no relations cannot hold it.
let spans: Int = 0
let k: Int = 0
while k < rc {
if str_eq(manifold_rel_name(m, k), "spans") {
if str_eq(manifold_rel_from(m, k), "interval:0-1") { spans = spans + 1 }
}
k = k + 1
}
let _c: Int = check(eq_int(spans, 2), "the interval is wired to both notes it spans")
println("a realizer returning non-geometry transduces nothing")
let rb: Int = realizer_register("bogus", "bogus_realizer")
let _c: Int = check(rb, "the symbol resolves, so registration succeeds")
let gb: Geometry = transduce("x", "bogus")
let gbi: Int = geometry_is(gb)
let _c: Int = check(1 - gbi, "contract enforced at the boundary: nothing handed back")
println("relation weight IS the grounding (correspondence-and-censorship §1)")
let wk: Int = 0
let found: Int = 0
while wk < rc {
if str_eq(manifold_rel_name(m, wk), "sounds_before") {
if near(manifold_rel_weight(m, wk), 0.8) > 0 { found = 1 }
}
wk = wk + 1
}
let _c: Int = check(found, "the ordering relation carries the weight its realizer stated")
println("norm lets a caller check a realizer emitted signal, not zeros")
let gn: Geometry = geometry_new(2)
let _c: Int = check(near(geometry_norm(gn), 0.0), "a fresh geometry is zero — norm says so")
let n0: Int = geometry_set(gn, 0, 3.0)
let n1: Int = geometry_set(gn, 1, 4.0)
let _c: Int = check(near(geometry_norm(gn), 5.0), "3-4-5: norm is 5")
let ffn: Int = geometry_free(gn)
println("the decomposition persists as real, separately addressable nodes")
let ids: [String] = el_list_empty()
let n0: Int = engram_node_count()
let e0: Int = engram_edge_count()
let pi: Int = 0
while pi < sz {
let key: String = manifold_key(m, pi)
let g: Geometry = manifold_geometry(m, pi)
let id: String = engram_node("component " + key, "Concept", 0.6)
let att: Int = node_attach_geometry(id, g)
ids = el_list_append(ids, id)
let ff: Int = geometry_free(g)
pi = pi + 1
}
let ri: Int = 0
while ri < rc {
let fi: Int = manifold_index_of(m, manifold_rel_from(m, ri))
let ti: Int = manifold_index_of(m, manifold_rel_to(m, ri))
engram_connect(el_list_get(ids, fi), el_list_get(ids, ti),
manifold_rel_weight(m, ri), manifold_rel_name(m, ri))
ri = ri + 1
}
let _c: Int = check(eq_int(engram_node_count() - n0, 5), "one signal became five nodes")
let _c: Int = check(eq_int(engram_edge_count() - e0, 6), "and six edges between them")
println("each part's geometry is independently readable back off its node")
let id_c: String = el_list_get(ids, manifold_index_of(m, "note:0"))
let id_iv: String = el_list_get(ids, manifold_index_of(m, "interval:0-1"))
let _c: Int = check(eq_int(node_geometry_dim(id_c), 2), "note:0 node carries a 2-wide geometry")
let _c: Int = check(eq_int(node_geometry_dim(id_iv), 1), "interval:0-1 node carries a 1-wide one")
println("one part can be grounded without touching its siblings")
let ear: String = engram_node("evidence: heard a C in the recording", "Memory", 0.7)
engram_connect(ear, id_c, 0.95, "corroborates")
let _c: Int = check(engram_edge_between(ear, id_c), "evidence attaches to note:0 specifically")
let id_g: String = el_list_get(ids, manifold_index_of(m, "note:2"))
let _c: Int = check(1 - engram_edge_between(ear, id_g), "and NOT to note:2 — the sibling is untouched")
// This is the whole gain, and it is impossible with a fingerprint: with one
// node per signal, "the C is corroborated" and "the G is not" have the same
// grounding target and cannot both be recorded.
let _c: Int = check(eq_int(node_geometry_dim(id_g), 2), "note:2 geometry is intact regardless")
println("a fingerprint realizer transduces NOTHING")
// #144's contract exactly: signal in, one Geometry out. It resolves, so the
// organ is present but it does not decompose, so it does not transduce.
// "No organ" and "an organ that only fingerprints" must not look alike.
let rf: Int = realizer_register("fingerprint", "fingerprint_realizer")
let _c: Int = check(rf, "the symbol resolves, so registration succeeds")
let mf: Manifold = transduce("x", "fingerprint")
let _c: Int = check(1 - manifold_is(mf), "a single vector is not a transduction")
println("the one-part case is a size-one manifold, not a bare vector")
let g1: Geometry = geometry_new(3)
let s1: Int = geometry_set(g1, 0, 5.0)
let ms: Manifold = manifold_single("level", "scalar", g1)
let _c: Int = check(manifold_is(ms), "manifold_single yields a real Manifold")
let _c: Int = check(eq_int(manifold_size(ms), 1), "of size one — visibly degenerate, not hidden")
let fg: Int = geometry_free(g1)
let fs: Int = manifold_free(ms)
println("no organ is still reported as no organ")
let me: Manifold = transduce("anything", "echolocation")
let _c: Int = check(1 - manifold_is(me), "no realizer means no manifold, not a fake one")
let fm: Int = manifold_free(m)
// Reaching here means nothing called exit(1) along the way.
println("")
+394 -23
View File
@@ -40,6 +40,7 @@
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h> /* SIGPIPE disposition: a hung-up client must not kill us */
#include <dlfcn.h> /* dlsym for http_set_handler fallback */
#include <unistd.h>
#include <fcntl.h>
@@ -1335,10 +1336,63 @@ static const char* http_reason_phrase(int status) {
}
}
/* Best-effort send with retry on partial writes. */
/* A DISCONNECTING CLIENT MUST NOT KILL THE SERVER (2026-08-16).
*
* There was no SIGPIPE handling anywhere in this runtime: no signal disposition,
* no MSG_NOSIGNAL, no SO_NOSIGPIPE, and send() called with bare flags. The
* default disposition of SIGPIPE is to TERMINATE THE PROCESS, so any client that
* hung up mid-response a curl that hit its timeout, a browser tab closed
* during a large read, a proxy giving up took the whole engram down with it.
*
* Measured on the live instance: 18 boots in the log, and `launchctl list`
* reporting the previous exit for ai.neuron.engram as -13, i.e. killed by
* signal 13 = SIGPIPE. Reproduced by the cause: pulling /api/nodes/list (26 MB)
* with a client-side timeout. launchd's KeepAlive then restarts it, so the
* failure looks like a mysterious restart rather than a crash, and the graph
* silently reloads under whatever was mid-flight.
*
* This is an exemption in the §8 sense: the write never checked whether the
* peer was still there, and the consequence of not checking was fatal rather
* than merely wrong.
*
* Two layers, because neither alone is portable:
* - SO_NOSIGPIPE per socket (Darwin/BSD) and MSG_NOSIGNAL per send (Linux),
* so the signal is never raised for socket writes in the first place.
* - A process-wide SIG_IGN as the backstop for platforms/paths with neither,
* installed once and idempotent. With the signal ignored, send() returns
* -1/EPIPE and the existing error path closes the connection. */
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
static void el_ignore_sigpipe_once(void) {
static int done = 0;
if (done) return;
done = 1;
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
}
/* Per-socket suppression where the platform offers it. Best-effort: a failure
* here is not fatal because el_ignore_sigpipe_once() already covers the case. */
static void el_sock_nosigpipe(int fd) {
#if defined(SO_NOSIGPIPE)
int on = 1;
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
#else
(void)fd;
#endif
}
/* Best-effort send with retry on partial writes. EPIPE/ECONNRESET are a client
* that left, not a server fault: return -1 so the caller closes the connection,
* and never let it reach the process as a signal. */
static int http_send_all(int fd, const char* p, size_t left) {
el_ignore_sigpipe_once();
while (left > 0) {
ssize_t w = send(fd, p, left, 0);
ssize_t w = send(fd, p, left, MSG_NOSIGNAL);
if (w < 0 && errno == EINTR) continue;
if (w <= 0) return -1;
p += w; left -= (size_t)w;
}
@@ -1788,6 +1842,7 @@ void http_serve(el_val_t port, el_val_t handler) {
pthread_mutex_unlock(&_http_conn_mu);
HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg));
if (!arg) { el_closesocket(cfd); continue; }
el_sock_nosigpipe(cfd);
arg->fd = cfd;
pthread_t tid;
if (pthread_create(&tid, NULL, http_worker, arg) != 0) {
@@ -1834,6 +1889,7 @@ static void* _http_serve_async_loop(void* raw) {
pthread_mutex_unlock(&_http_conn_mu);
HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg));
if (!arg) { close(cfd); continue; }
el_sock_nosigpipe(cfd);
arg->fd = cfd;
pthread_t tid;
if (pthread_create(&tid, NULL, http_worker, arg) != 0) {
@@ -2134,6 +2190,7 @@ void http_serve_v2(el_val_t port, el_val_t handler) {
pthread_mutex_unlock(&_http_conn_mu);
HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg));
if (!arg) { el_closesocket(cfd); continue; }
el_sock_nosigpipe(cfd);
arg->fd = cfd;
pthread_t tid;
if (pthread_create(&tid, NULL, http_worker_v2, arg) != 0) {
@@ -6233,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 namesymbol step rides the identical, already load-bearing mechanism
* http_set_handler uses (see "HTTP server"): every El `fn name(...)` compiles
@@ -6323,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 ──────────────────────────────── */
+60 -10
View File
@@ -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.
+440 -140
View File
@@ -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)
}