7a1501d097
El SDK CI - dev / build-and-test (pull_request) Failing after 3m59s
A relation that keeps holding up strengthens; one that stops corresponding
decays. That is not analogous to grounding, it IS grounding — so it belongs on
the edge, not in a subsystem beside it. The graph was already the grounding
structure; this stops modelling it as something else.
Deleted, not refactored:
- cog_ground_edge and the `grounded-by` relation type. A grounded-by edge
models grounding as a relation BETWEEN nodes when it is a property OF a
relation. #147 fixed which endpoints that edge landed on and left the wrong
idea intact. Measured on the live store: the old path scored two nodes with
ZERO edges between them at 0.925237 and wrote an edge for it.
- ground() writing. It was a read that wrote — the eg_vindex_sync defect.
Three identical calls produced three writes to the same edge id.
- keystone_write_blocked. Its measured cost was 0.00% brier reduction over
n_trials 0 on the keystone: the loop never ran, so the self was never
calibrated and never falsifiable. Nothing replaces it — non-circularity of
the reference frame is temporal, not a permission.
- a graph predicate for "evidence downstream of itself", built and then
withdrawn. Reachability from the self region covers 89.2% of the live graph
(10,580 of 11,861 nodes), so any topological predicate marks nearly all
evidence tainted and degenerates into the total block censorship began as.
The vector, carried in a GRD1 block on the edge's own metadata:
factual, relational, associative (the existing hebb), polarity (SIGNED — near
zero is "no support", negative is "actively contradicts"; `inhibitory` is that
distinction crushed to one bit), provenance class, and a timestamp. Confidence,
recency, staleness and volatility are DERIVED at read and never serialized.
Decay is one model, not two: cog_decay_factor is the single implementation and
engram_temporal_decay now delegates to it — proven bit-identical over 24
(age, reinforcement) points.
Values reference: thirteen regions, aggregate MIN, binding value named. Measured
— the 13 have pairwise centroid cosine min 0.1525 / mean 0.5199 / max 0.9278, so
they demonstrably are not one region, and a mean would let agreement with twelve
mask a violation of the thirteenth.
Supersession versions the whole vector jointly, gated by consequence and
salience with no epsilon anywhere: floor crossings and sign changes only.
Polarity flips and provenance-class changes are inherently significant and
bypass the salience gate.
Also fixed: the frame contract. Descriptors are built over L2-normalized member
embeddings; think() and the grounding path were fitting RAW vectors against them.
Measured on the self region, same data, same 106 members:
magnitude 0.00283443 -> 0.536134, spread 18.7565 -> 0.930163.
Every fit score sat three decimal places below the 0.5 floors that gate on them.
assert() gates on both floors and computes still_held instead of returning a
hardcoded `true` — the old build reported still_held for a node that does not
exist.
177 lines
8.1 KiB
C
177 lines
8.1 KiB
C
/* test_grounding_vector.c — deterministic tests for §7: the one decay model, the
|
|
* consequence gate, and the stored/derived split. Links engram_cognition.c
|
|
* directly; no server, no store, no network. See run_grounding_vector_tests.sh.
|
|
*
|
|
* NEGATIVE CONTROL (invariant §8.6). Every symbol exercised here —
|
|
* cog_decay_factor, cog_grounding_significant, cog_significance_inherent,
|
|
* CogGrounding, CogProvClass — is introduced by the change under test, so this
|
|
* suite does not COMPILE against the pre-change source, let alone pass. The
|
|
* runner documents the exact reproduction.
|
|
*/
|
|
#include "engram_cognition.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
static int fails = 0;
|
|
static void ok(int cond, const char* what) {
|
|
printf(" %-62s %s\n", what, cond ? "PASS" : "*** FAIL ***");
|
|
if (!cond) fails++;
|
|
}
|
|
|
|
/* The decay formula exactly as el_runtime.c carried it before the move, so the
|
|
* refactor can be shown to be bit-identical rather than merely similar. */
|
|
static double old_engram_temporal_decay(long long age_ms, long long activation_count,
|
|
double temporal_decay_rate) {
|
|
if (age_ms <= 0) return 1.0;
|
|
double lambda = (temporal_decay_rate > 0.0) ? temporal_decay_rate : 0.693147;
|
|
double age_hours = (double)age_ms / 3600000.0;
|
|
double t_half = 168.0 * (1.0 + log(1.0 + (double)activation_count));
|
|
double factor = exp(-lambda * age_hours / t_half);
|
|
if (factor < 0.25) factor = 0.25;
|
|
return factor;
|
|
}
|
|
|
|
static CogGrounding base(void) {
|
|
CogGrounding g; memset(&g, 0, sizeof g);
|
|
g.present = 1;
|
|
g.factual = 0.60; g.relational = 0.60;
|
|
g.factual_now = 0.60; g.relational_now = 0.60;
|
|
g.associative = 0.1; g.polarity = 1.0;
|
|
g.prov = COG_PROV_TOLD;
|
|
g.fac_proj = 1.0; g.rel_proj = 1.0;
|
|
g.cos_angle = 0.9; g.agreement = 1;
|
|
g.ts = 1000; g.seq = 1; g.reinforcements = 3;
|
|
return g;
|
|
}
|
|
|
|
int main(void) {
|
|
const double F = 0.5, R = 0.5;
|
|
|
|
printf("\n== 1. DECAY IS THE ONE MODEL, AND IT IS BIT-IDENTICAL TO WHAT IT REPLACED ==\n");
|
|
{
|
|
long long ages[] = {0, 3600000LL, 86400000LL, 7*86400000LL, 30*86400000LL, 365*86400000LL};
|
|
int allsame = 1;
|
|
for (int i = 0; i < 6; i++)
|
|
for (int ac = 0; ac < 4; ac++) {
|
|
long long acs[] = {0, 1, 10, 1000};
|
|
double a = cog_decay_factor(ages[i], (double)acs[ac], 0.0);
|
|
double b = old_engram_temporal_decay(ages[i], acs[ac], 0.0);
|
|
if (a != b) allsame = 0;
|
|
}
|
|
ok(allsame, "cog_decay_factor == the pre-move engram_temporal_decay (24 pts)");
|
|
ok(cog_decay_factor(0, 0, 0.0) == 1.0, "age 0 -> no decay");
|
|
}
|
|
printf("\n DECAY OVER ELAPSED TIME (reinforcements = 0, default rate):\n");
|
|
printf(" %10s %10s\n", "elapsed", "decay");
|
|
{
|
|
struct { const char* label; long long ms; } pts[] = {
|
|
{"0", 0LL},
|
|
{"1 hour", 3600000LL},
|
|
{"1 day", 86400000LL},
|
|
{"3 days", 3LL*86400000LL},
|
|
{"7 days", 7LL*86400000LL},
|
|
{"14 days", 14LL*86400000LL},
|
|
{"30 days", 30LL*86400000LL},
|
|
{"90 days", 90LL*86400000LL},
|
|
};
|
|
double prev = 2.0; int monotone = 1;
|
|
for (unsigned i = 0; i < sizeof pts / sizeof pts[0]; i++) {
|
|
double d = cog_decay_factor(pts[i].ms, 0, 0.0);
|
|
printf(" %10s %10.6f\n", pts[i].label, d);
|
|
if (d > prev) monotone = 0;
|
|
prev = d;
|
|
}
|
|
ok(monotone, "decay is monotone non-increasing in elapsed time");
|
|
ok(fabs(cog_decay_factor(7LL*86400000LL, 0, 0.0) - 0.5) < 1e-6,
|
|
"7 days at zero reinforcements == exactly one half-life (0.5)");
|
|
ok(cog_decay_factor(7LL*86400000LL, 100, 0.0) > cog_decay_factor(7LL*86400000LL, 0, 0.0),
|
|
"reinforcement slows ageing (Lindy term)");
|
|
ok(cog_decay_factor(3650LL*86400000LL, 0, 0.0) == 0.25,
|
|
"floor is a preference not a cliff: bottoms out at 0.25");
|
|
}
|
|
|
|
printf("\n== 2. CONSEQUENCE GATE: EVERY TRIGGER, AND NO EPSILON ANYWHERE ==\n");
|
|
{
|
|
CogGrounding p = base(), n = base();
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_NONE,
|
|
"identical vectors -> NONE (a re-read must not consolidate)");
|
|
|
|
n = base(); n.factual = 0.9999; n.factual_now = 0.9999;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_NONE,
|
|
"factual 0.60 -> 0.9999 without crossing the floor -> NONE");
|
|
|
|
n = base(); n.relational = 0.5001; n.relational_now = 0.5001;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_NONE,
|
|
"relational 0.60 -> 0.5001, still above floor -> NONE");
|
|
|
|
n = base(); n.factual_now = 0.4999;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_FACTUAL_FLOOR,
|
|
"a 0.1001 drop that CROSSES the floor -> FACTUAL_FLOOR");
|
|
|
|
n = base(); n.relational_now = 0.4999;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_RELATIONAL_FLOOR,
|
|
"relational crossing its floor -> RELATIONAL_FLOOR");
|
|
|
|
n = base(); n.cos_angle = -0.05; n.agreement = -1;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_AGREEMENT_FLIP,
|
|
"agreement +1 -> -1 -> AGREEMENT_FLIP");
|
|
|
|
n = base(); n.fac_proj = -0.2;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_DIRECTION_REVERSAL,
|
|
"factual gradient reverses -> DIRECTION_REVERSAL");
|
|
|
|
n = base(); n.rel_proj = -0.2;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_DIRECTION_REVERSAL,
|
|
"relational gradient reverses -> DIRECTION_REVERSAL");
|
|
|
|
n = base(); n.polarity = -1.0;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_POLARITY_FLIP,
|
|
"support -> contradiction -> POLARITY_FLIP (inherent)");
|
|
|
|
n = base(); n.polarity = 0.0;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_POLARITY_FLIP,
|
|
"support -> ignorance (zero) -> POLARITY_FLIP: not the same state");
|
|
|
|
n = base(); n.prov = COG_PROV_OBSERVED;
|
|
ok(cog_grounding_significant(&p, &n, F, R) == COG_SIG_PROVENANCE_CHANGE,
|
|
"told -> observed -> PROVENANCE_CHANGE (inherent)");
|
|
|
|
CogGrounding fresh; memset(&fresh, 0, sizeof fresh);
|
|
ok(cog_grounding_significant(&fresh, &n, F, R) == COG_SIG_FIRST_RECORD,
|
|
"no prior version -> FIRST_RECORD");
|
|
}
|
|
|
|
printf("\n== 3. INHERENT MOVES BYPASS THE SALIENCE GATE ==\n");
|
|
ok(cog_significance_inherent(COG_SIG_POLARITY_FLIP), "polarity flip is inherent");
|
|
ok(cog_significance_inherent(COG_SIG_PROVENANCE_CHANGE), "provenance change is inherent");
|
|
ok(cog_significance_inherent(COG_SIG_FIRST_RECORD), "first record is inherent");
|
|
ok(!cog_significance_inherent(COG_SIG_FACTUAL_FLOOR), "a floor crossing is NOT inherent");
|
|
ok(!cog_significance_inherent(COG_SIG_NONE), "NONE is not inherent");
|
|
|
|
printf("\n== 4. THE STORED/DERIVED SPLIT: DERIVED VALUES ARE NEVER SERIALIZED ==\n");
|
|
{
|
|
CogGrounding g = base();
|
|
g.decay = 0.3333; g.factual_now = 0.1234; g.relational_now = 0.2345;
|
|
g.associative_now = 0.4567; g.age_ms = 999999; g.stale = 1;
|
|
char* m = cog_grounding_metadata("pre-existing=keepme", &g);
|
|
ok(m != NULL, "serializer returns a document");
|
|
ok(m && strstr(m, "pre-existing=keepme"), "pre-existing edge metadata preserved verbatim");
|
|
ok(m && strstr(m, "GRD1"), "GRD1 magic present");
|
|
ok(m && !strstr(m, "0.3333"), "decay is NOT stored");
|
|
ok(m && !strstr(m, "0.1234"), "factual_now is NOT stored");
|
|
ok(m && !strstr(m, "0.2345"), "relational_now is NOT stored");
|
|
ok(m && !strstr(m, "0.4567"), "associative_now is NOT stored");
|
|
ok(m && !strstr(m, "999999"), "age is NOT stored");
|
|
ok(m && strstr(m, "told"), "provenance class IS stored");
|
|
ok(m && strstr(m, "0.6"), "the factual/relational dimensions ARE stored");
|
|
if (m) { printf("\n --- serialized GRD1 block ---\n%s -----------------------------\n", m); }
|
|
free(m);
|
|
}
|
|
|
|
printf("\n%s (%d failure%s)\n\n", fails ? "SOME TESTS FAILED" : "ALL TESTS PASSED",
|
|
fails, fails == 1 ? "" : "s");
|
|
return fails ? 1 : 0;
|
|
}
|