/* engram_cognition.h — THE ONE OPERATION. * * The buildable form of the "cognition is one operation" theory (design doc * engram/spec/cognitive-architecture.design.md; memory bdc8a488 / d582a766). * * Cognition is ONE operation — think — a directed traversal-READ of the geometry * from an anchor, steered by a learned STANCE, whose output is a GRADIENT (a * direction + spread over the geometry), never a point. The named faculties * (reason / induce / abduce / analogy / relate / plan / ground) are human LABELS * on regions of think's steering space: each faculty == { think + a named stance }. * Collapse-to-a-point happens only at EXPRESSION (a separate faculty), never in think. * * NAMING (Will's directive): the surface verbs name the cognitive ACT being * performed (think / reason / induce / ground / verify), not the internal function * shape. The single frozen primitive underneath every faculty is engram_think, * which composes over engram_reason_point_fit + the §5 geo-algebra. Those never * learn. Only the STANCE learns. * * "Stance" is the theory's steering PRIOR, deliberately named distinctly: in this * codebase the token "prior" already means previous-VERSION (supersession). A * Stance is a learnable bias/disposition over the geometry — which axes matter, * which way pays off, plus a calibrated track record — attached to a faculty-label * and a region, and grounded-for-whom. * * PURE + (mostly) READ-ONLY, stdlib + libm only. think() and the warp are pure * over their inputs. Persistence (Stance <-> StoreNode, edge grounding vectors) is the * only part that touches the store, and it is additive / supersede / tombstone — * never mutate-in-place, never delete. It NEVER touches the live daemon: all * offline against a scratch store, per the design's rails. */ #ifndef ENGRAM_COGNITION_H #define ENGRAM_COGNITION_H #include #include #include "engram_geometry.h" #include "engram_reason.h" #include "engram_store.h" /* Max principal axes a stance warps (matches GeoParams.top_axes default budget). */ #define COG_MAX_AXES 32 /* ═══════════════════════════════════════════════════════════════════════════ * §1 GeoGradient — the OUTPUT of think. A direction + spread over the geometry, * plus the calibrated confidence and the read it was computed against. NOT a point. * A spiked gradient (spread→0) = "exact" (deduction); a spread gradient = "fuzzy" * (prediction). The gradient is ALSO the next steering direction (closed-loop flow). * ═══════════════════════════════════════════════════════════════════════════ */ typedef struct { int dim; float* direction; /* unit steering vector in the anchor's frame (owned) */ double spread; /* 0 = spiked/exact ... large = diffuse/fuzzy */ double confidence; /* calibrated, from the stance's track record (reliab.) */ double magnitude; /* THIS read's own membership/fit estimate ∈(0,1]. * The scalar an expression faculty would SAMPLE; kept * on the gradient but never used AS a decision by think.*/ const char* anchor_id; /* borrowed: the vantage this was read from */ int n_support; /* neighborhood members that shaped the read */ const char* stance_id; /* borrowed: which stance steered this (provenance) */ } GeoGradient; void engram_gradient_free(GeoGradient* g); /* ═══════════════════════════════════════════════════════════════════════════ * §2 Stance — the learnable steering prior, as a first-class object. In memory * here; persisted as a StoreNode (node_type "Stance") via cog_stance_*serialize. * * warp: axis_gain[] per-principal-axis multiplier on extents (which axes * matter — gain>1 WIDENS an axis so it penalizes less); * bias_dir[] a steering-direction seed in the region's frame; * scalars faculty constants this stance overrides (ext_floor, etc). * calibration: the track record — the ONLY thing the loop (§4) updates * besides warp: n_trials, a Brier accumulator, reliability * (→ GeoGradient.confidence), and an EMA error. * keystone: if set, the correspondence-loop MUST NEVER write warp or * calibration — read-mostly (self / values). §6 metastability. * ═══════════════════════════════════════════════════════════════════════════ */ typedef struct { char* id; /* stance node id (owned) */ char* faculty; /* the act this stance serves: "induce"|"relate"|... */ char* anchor_region; /* node/neighborhood id this stance is attached to */ char* for_whom; /* observer id — grounding is relational (NULL=global) */ int keystone; /* 1 = read-mostly, loop never writes it (§6) */ int dim; /* embedding dim of the region */ int n_axes; /* how many axis_gain entries are live (<= COG_MAX_AXES)*/ double axis_gain[COG_MAX_AXES]; /* per-axis extent multipliers (init 1.0) */ float* bias_dir; /* dim floats, steering seed (owned; NULL = none) */ double ext_floor; /* faculty scalar: the extent floor (init 1.0) */ double drop_frac; /* faculty scalar (causal): confound drop (init 0.5) */ double assoc_floor; /* faculty scalar (causal): assoc floor (init 0.2) */ /* calibration / track record */ int64_t n_trials; double brier_sum; /* Σ (p − y)² */ double reliability; /* calibrated ∈[0,1] → GeoGradient.confidence */ double ema_error; /* EMA of per-trial error */ double last_error; } CogStance; /* Initialize a neutral stance (all gains 1.0, default scalars, reliability 0.5). * dim/n_axes taken from the region descriptor. faculty/id/for_whom are copied. */ int cog_stance_init(CogStance* s, const char* id, const char* faculty, const char* anchor_region, const char* for_whom, const GeoDescriptor* region); void cog_stance_free(CogStance* s); /* A stance set to today's hard-coded constants == behavioral parity with the * pre-stance operators (axis_gain all 1.0, ext_floor default, drop_frac 0.5, * assoc_floor 0.2). This is the FROZEN CONTROL used by the validation. */ void cog_stance_set_frozen_defaults(CogStance* s); /* ── Serialization: Stance <-> StoreNode (compact line schema "STNC1", mirroring * the reify "GEO1" precedent). Additive; the node's importance field caches the * reliability readout. Round-trips exactly (reboot-prove). ──────────────────── */ char* cog_stance_to_metadata(const CogStance* s); /* owned string */ int cog_stance_to_node(const CogStance* s, StoreNode* out);/* fills a StoreNode */ int cog_stance_from_node(const StoreNode* n, CogStance* out);/* parse STNC1 */ #define COG_STANCE_NODE_TYPE "Stance" #define COG_STANCE_META_MAGIC "STNC1" /* ═══════════════════════════════════════════════════════════════════════════ * §1.2 think — the ONE operation. Frozen procedure over three steps: * 1. re-origin on the anchor point (the vantage; the manifold is the read * neighborhood, passed as `region`); * 2. fit the anchor under the stance's WARP (engram_reason_point_fit with the * axis extents multiplied by axis_gain and ext_floor substituted); * 3. emit a GRADIENT: direction = the warped steepest-descent that reduces the * fit distance (the "which way pays off" seed + bias_dir), spread from the * fit distance, confidence from the stance's reliability, magnitude = the * read's membership estimate. NO point-collapse — that is expression. * * `region` — the read neighborhood (built by vantage_read / geometry descriptor). * `anchor` — the point to read FROM (dim floats). NULL = region centroid (self). * `stance` — the steering prior. NULL = neutral (frozen defaults) => parity. * Returns 0 and fills `out` (engram_gradient_free), <0 on error. * ═══════════════════════════════════════════════════════════════════════════ */ int engram_think(const GeoDescriptor* region, const float* anchor, const CogStance* stance, GeoGradient* out); /* The warped fit itself (step 2), exposed for the loop + verifier reuse. Identical * to engram_reason_point_fit when stance==NULL or all gains==1 && ext_floor default. */ int cog_warped_fit(const GeoDescriptor* region, const float* x, const CogStance* stance, GeoFit* out); /* EXPRESSION — the ONLY place a gradient collapses to a point. Samples the gradient * off the anchor along its steering direction, scaled by (1 − spread) so a spiked * (confident) gradient lands a definite point and a diffuse one barely moves. * This is deliberately a SEPARATE faculty from think (§1.2, M5). */ int engram_express(const GeoGradient* g, const float* anchor, float* out_point); /* ═══════════════════════════════════════════════════════════════════════════ * §5 HOLD vs GROUND vs ASSERT. Holding is unconditional (the store gates nothing). * Grounding is an ATTRIBUTE OF a relation — carried on the edge itself, as a * vector (§7). The honesty floor is checked only at ASSERTION, on both axes. * ═══════════════════════════════════════════════════════════════════════════ */ /* DELETED 2026-08-16: COG_GROUNDED_BY_RELATION and cog_ground_edge. * * A "grounded-by" edge models grounding as a relation BETWEEN two nodes. It is a * property OF a relation — and it is that relation's weight. Minting a new edge * to carry a score was the error; #147 corrected which endpoints the edge landed * on and left the wrong idea standing. There is nothing to ground a claim * "against" that is not already an edge, and if no edge exists the honest answer * is that the two are not related — not a freshly minted one scoring 0.98. * See §7 for what replaced it. */ #define COG_SALIENT_TO_RELATION "salient-to" /* Write/refresh a salient-to edge: salience is RELATIONAL (grounded-for-whom), * carried on the edge to the observer — not baked into the node scalar (§2.1). */ int cog_salient_edge(EngramPagedStore* s, const char* node_id, const char* observer_id, double salience); /* ═══════════════════════════════════════════════════════════════════════════ * §4 THE REFLEXIVE CORRESPONDENCE-LOOP — the learning engine. think scores its * OWN gradient against outcome, refines the stance on the error, and (optionally) * writes the (gradient, outcome, error) back as self-describing geometry. This is * the dormant verifier turned INWARD. * * grade(1) SELF-CONSISTENCY (no external world-labels): the outcome is what the * geometry itself says — the membership determined by the region's SIGNAL subspace * (the axes reality actually weights). The stance's cheap warped read is graded * against that geometric truth; error refines the warp so the read corresponds. * ═══════════════════════════════════════════════════════════════════════════ */ typedef struct { double correspondence; /* ∈[0,1]: 1 − |p − y| for this trial */ double error; /* 1 − correspondence */ double brier; /* running mean (p − y)² across the stance's trials */ double reliability; /* the stance's current calibrated reliability */ int wrote_keystone; /* 1 iff a keystone update was BLOCKED (safety audit) */ } CogBeatResult; /* One correspondence beat for ONE trial: * think(region, anchor, stance) -> gradient (a PREDICTION, ungrounded) * outcome y := grade-1 self-consistency target (in [0,1]) * error = |magnitude − y|; refine stance.warp + calibration on the error * (bounded step; NEVER writes a keystone stance) * `learn`==0 grades WITHOUT updating (the frozen-control path). `max_step` bounds * the per-beat warp change (metastability; §6). Returns 0 / <0. */ int engram_correspondence_beat(const GeoDescriptor* region, const float* anchor, double outcome_y, CogStance* stance, int learn, double max_step, CogBeatResult* out); /* ═══════════════════════════════════════════════════════════════════════════ * §6 METASTABILITY. Keystones (self/values) are read-mostly: the loop reads but * never writes them. Mark by stance flag or by a keystone-id set the loop consults. * * SUPERSEDED BY §7's PROVENANCE CONSTRAINT (2026-08-16). The keystone flag is a * PERMISSION: it asks who the target is, not where the evidence came from. That * is censorship, and it costs the ability to ever ground the self (spec * correspondence-and-censorship.md §0/§2). The constraint that actually protects * a reference frame is cog_grounding_downstream: a region may not be calibrated * by evidence downstream of itself. These declarations remain only so existing * call sites keep compiling; nothing in the grounding path consults them. * ═══════════════════════════════════════════════════════════════════════════ */ typedef struct { const char** ids; int n; } CogKeystoneSet; int cog_is_keystone(const CogKeystoneSet* ks, const CogStance* s); /* ═══════════════════════════════════════════════════════════════════════════ * §7 GROUNDING IS THE EDGE'S WEIGHT, AND THE WEIGHT IS A VECTOR * (2026-08-16; spec correspondence-and-censorship.md §2–§6 @ 2b7e4ba.) * * THE MODEL. Grounding is not a subsystem, a score, or a relation BETWEEN nodes. * It is an attribute OF a relation. The graph already IS the grounding structure: * every edge is a grounded relation, and what that relation is worth is carried * on the edge itself. Three things follow, and each DELETES rather than adds: * * 1. `grounded-by` as a relation type does not exist, and cog_ground_edge is * gone. Minting an edge to hold a score models grounding as a relation * between nodes when it is a property of a relation. #147 corrected which * endpoints that edge landed on and left the wrong idea standing. * 2. There is no observer, and no sampling rate. Change is not a consequence of * use — it IS use, the way potentiation is the firing rather than something * that reads the firing and writes a weight. So no supervisor compares a * value to a threshold and decides to persist. * 3. Between two recorded versions the trajectory is not unknown. Decay is a * pure function of the last recorded point and elapsed time, so it is * ANALYTIC: store the point, read the curve. * * WHAT IS *NOT* HERE, DELIBERATELY. An earlier draft of the spec posed "a graph * predicate for evidence downstream of itself" as the hard problem, and this file * briefly contained one. It is withdrawn. Non-circularity is TEMPORAL, not * topological: you cannot recalibrate the ruler while measuring with it, so you * do it when you are not using the frame to act. Reachability could never have * worked — measured on the live store, reachability from the self region over * all relations reaches 89.2% of the graph (10,580 of 11,861 nodes) and 16.0% * over hebbian/semantic relations alone, so the predicate marks essentially all * evidence tainted and the constraint degenerates into the total block that * censorship started as. Nothing replaces it here; the independence is a fact * about engagement, owned by the dreamer, not a fact about the graph. * * ═══════════════════════════════════════════════════════════════════════════ * §7.1 THE VECTOR * * The test for a real dimension is whether it can move independently of the * others. Five can, and each maps onto substrate that already exists: * * factual correspondence with evidence. [GRD1] * relational correspondence with values — min over THIRTEEN * value regions, carrying the binding value's NAME. [GRD1] * associative co-activation frequency. This is the edge's `hebb` * field with its existing dynamics — NOT a new one. * Independent by construction: every superstition is * a strong association with no factual grounding. * polarity SIGNED. Near zero means "no support"; NEGATIVE means * "this actively contradicts". The edge's `inhibitory` * bit is exactly this distinction crushed to one bit, * and is carried forward as the seed value. [GRD1] * provenance observed / inferred / told / imprinted. Categorical, * and load-bearing: it governs what the relation is * entitled to. [GRD1] * * Plus a TIMESTAMP, which is what turns the supersession chain into a time * series of vectors rather than a series of numbers. * * DERIVED, THEREFORE NEVER STORED. Confidence (high grounding AND low * volatility), recency (decay read off the curve), staleness (grounding fallen * below its floor), volatility (the derivative of a series nothing destroyed). * Storing confidence separately is how `confidence: 0.5` ends up sitting beside * a zero direction vector, asserting something nothing computed. Every field in * CogGrounding below is marked STORED or DERIVED, and the serializer writes * only the STORED ones. * * THE VALUES REFERENCE IS THIRTEEN REGIONS AND THE AGGREGATE IS MIN. * Measured on the live store: the values root kn-5b606390 `contains` exactly 13 * value nodes; pairwise centroid cosine among their regions is min 0.1525, * mean 0.5199, median 0.5282, max 0.9278 — they demonstrably do not form one * region. Against a single union region the individual values sit at cosine * 0.38..0.89, with constraints-as-freedom at 0.3812 and change-is-the-signal at * 0.4677, so a union centroid under-represents precisely the values a claim is * most likely to be measured against. MIN rather than MEAN because a mean lets * strong agreement with twelve values mask a violation of the thirteenth, which * is the mechanism of rationalization; min yields a binding constraint with a * NAME attached rather than a score. * * TRAVERSAL CONDUCTS ON FACTUAL; ASSERTION REQUIRES BOTH. If activation * conducted on relational weight, Neuron could not follow a chain of reasoning * to a conclusion he then rejects — censorship arriving through the spreading * rule. The gap between reachable and assertable is where the wide * factual/relational angles live, and that gap is the interesting part. * ═══════════════════════════════════════════════════════════════════════════ */ /* ── The one decay model (moved here from el_runtime.c so that node decay and * edge-grounding decay are a single implementation with a single set of * constants, rather than a model and a parallel copy of it). Half-life scales * with how established the thing is: T_eff = T_HALF · (1 + ln(1 + reinforcements)). * The floor is a preference, not a cliff — max penalty for age alone is 4x. * `lambda_override` > 0 replaces the default rate; 0 means use the default. */ #define COG_T_HALF_HOURS 168.0 #define COG_DECAY_LAMBDA 0.693147 #define COG_DECAY_FLOOR 0.25 double cog_decay_factor(int64_t age_ms, double reinforcements, double lambda_override); /* The compact vector block carried in the edge's own metadata. Line schema, same * precedent as STNC1 / GEO1. Metadata the edge already carried is preserved * verbatim ahead of the magic line. */ #define COG_GROUNDING_META_MAGIC "GRD1" /* Provenance class — categorical, and it governs what the relation is entitled * to. A change of class is inherently significant and needs no threshold, * because told → observed is a categorical upgrade, not a drift. */ typedef enum { COG_PROV_UNSET = 0, COG_PROV_OBSERVED = 1, COG_PROV_INFERRED = 2, COG_PROV_TOLD = 3, COG_PROV_IMPRINTED = 4 } CogProvClass; const char* cog_prov_name(CogProvClass p); CogProvClass cog_prov_parse(const char* s); typedef struct { int present; /* 1 iff the edge carries a GRD1 block */ /* ── STORED: the vector, as it stood at `ts` ─────────────────────────────── */ double factual; /* correspondence with evidence */ double relational; /* min over the thirteen value regions */ double associative; /* co-activation frequency — mirrors edge->hebb */ double polarity; /* SIGNED support; <0 = actively contradicts */ CogProvClass prov; /* observed / inferred / told / imprinted */ int64_t ts; /* when this version was recorded (ms) */ int64_t seq; /* supersession sequence number */ double reinforcements; /* uses folded into this version */ char binding_value[128]; /* the argmin value — the conflict's NAME */ /* the two gradients as frame-independent signed projections, plus the angle * between them in full R^dim. These are part of the JOINT STATE a decision * saw, not a convenience: near +1 evidence and values push the same way; at * or below 0 the relation is factually supported and relationally wrong. */ double fac_proj, rel_proj, cos_angle; int agreement; /* sign(cos_angle): +1 / 0 / −1 */ double floor_at_record, rel_floor_at_record; char prev_edge[192]; /* the version this superseded ("" if first) */ /* ── DERIVED at read time. NEVER serialized. ─────────────────────────────── */ int64_t age_ms; /* recency: now − ts */ double decay; /* cog_decay_factor over that age */ double factual_now; /* factual · decay */ double relational_now; double associative_now; int stale; /* grounding fallen below its floor */ } CogGrounding; /* Read an edge's vector as of `now_ms`. Pure — never writes. An edge with no * GRD1 block still has an associative strength (its accrued hebb) and a polarity * (its signed authored weight); `present` says whether the grounding dimensions * have ever been established, and an unestablished dimension is reported as such * rather than defaulted to a passing value. */ int cog_grounding_parse(const StoreEdge* e, int64_t now_ms, CogGrounding* out); /* Serialize the STORED half of the vector, preserving pre-existing non-GRD1 * metadata. Returns an owned string. Derived fields are not written. */ char* cog_grounding_metadata(const char* base_meta, const CogGrounding* g); /* ── §7.2 CONSOLIDATION-GATED SUPERSESSION ────────────────────────────────── * * Supersession is not recording — it is CONSOLIDATION, gated by salience, which * is why you remember the argument and not the commute. Significance is * evaluated PER-DIMENSION but the record is the WHOLE VECTOR: any dimension * moving enough to matter triggers a supersession, and the new version captures * every dimension as it stood at that instant. Versioning axes independently * would make the joint state unreconstructable, and the joint state is the point * — it is what makes "stayed true, became wrong" visible as an event (factual * holding steady across versions while relational degrades). * * There is deliberately no epsilon in this enum or in the function that computes * it. Every test is a floor crossing or a sign change, both exact. Two of them * are INHERENTLY significant because they are discrete state changes rather than * drift, and those bypass the salience gate entirely. */ typedef enum { COG_SIG_NONE = 0, /* nothing decision-relevant moved — DO NOT RECORD */ COG_SIG_FIRST_RECORD = 1, /* no prior version exists */ COG_SIG_POLARITY_FLIP = 2, /* INHERENT: support ↔ contradiction, or ignorance * ↔ either. A discrete change of state. */ COG_SIG_PROVENANCE_CHANGE = 3, /* INHERENT: told → observed is a categorical * upgrade in what the relation is entitled to. */ COG_SIG_FACTUAL_FLOOR = 4, /* crossed the assert floor, factual axis */ COG_SIG_RELATIONAL_FLOOR = 5, /* crossed the assert floor, relational axis */ COG_SIG_AGREEMENT_FLIP = 6, /* factual/relational agreement changed sign */ COG_SIG_DIRECTION_REVERSAL = 7 /* a gradient reversed direction */ } CogSignificance; CogSignificance cog_grounding_significant(const CogGrounding* prev, const CogGrounding* now, double floor, double rel_floor); const char* cog_significance_name(CogSignificance s); /* 1 iff this reason is a discrete state change that consolidates regardless of * salience (polarity flip, provenance change, first record). */ int cog_significance_inherent(CogSignificance s); /* ── §7.3 RECORDING: supersession of the EDGE, never an overwrite ──────────── * Writes version seq+1 as a NEW edge record with the same endpoints and relation * and id "#", carrying a GRD1 `p` pointer to its predecessor. The * predecessor is never touched. The chain IS the trajectory: not only what the * grounding is but which way it has been moving and how fast — a derivative * obtained for free from immutability, because the points were never destroyed. * Returns the version written (>=1), or <0 on error. */ int cog_grounding_record(EngramPagedStore* s, const StoreEdge* base, const CogGrounding* g, char* out_id, size_t out_id_cap); /* Walk forward from a base edge id to its newest recorded version. Point reads * only; consolidation is gated, so the chain is short. Returns the highest * version found (0 = the base record is the only one). */ int cog_grounding_head(EngramPagedStore* s, const char* base_id, StoreEdge* out, int max_versions); /* VOLATILITY — derived, never stored: the mean absolute per-version change of a * dimension across the recorded chain. Feeds the equally-derived `confidence` * (high grounding AND low volatility), which is likewise never stored. */ typedef struct { int n_versions; double factual_volatility; double relational_volatility; double factual_drift; /* signed: newest − oldest */ double relational_drift; int stayed_true_became_wrong; /* factual steady while relational degraded */ } CogTrajectory; int cog_grounding_trajectory(EngramPagedStore* s, const char* base_id, int64_t now_ms, CogTrajectory* out); /* ── §7.4 ASSERTION GATES ON BOTH FLOORS ──────────────────────────────────── * A well-evidenced claim must not earn the right to be asserted regardless of * whether it means the right thing. `may_assert` requires the decayed factual * grounding to clear `floor` AND the decayed relational grounding to clear * `rel_floor`. A relation whose relational axis has never been established does * not pass by default — it is reported unestablished and refused, because * defaulting it to passing is exactly the exemption §0 forbids. Traversal is * untouched: activation still conducts on the factual/associative side, so a * relation can remain thinkable while ceasing to be assertable. */ typedef struct { int may_assert; int found; /* any relation at all on this claim */ int relational_established; int still_held; /* DERIVED: node present and not tombstoned */ double factual; /* best decayed factual grounding */ double relational; /* the SAME edge's relational axis, not a max */ double polarity; double cos_angle; int agreement; CogProvClass prov; char best_edge[192]; char binding_value[128]; int n_edges; } CogAssertion; int cog_assert_two_axis(EngramPagedStore* s, const char* claim_id, double floor, double rel_floor, int64_t now_ms, CogAssertion* out); #endif /* ENGRAM_COGNITION_H */