01826421c4
Will waived diff review -> build it for real. Add engram_boundary_beat() to the runtime (afferent counter++ + engram_chrono_tick + engram_strengthen(self-anchor) + dharma_emit) and two act-stats counters (aff_boundary_ops, dharma_emits). codegen cg_fn injects ONE engram_boundary_beat(op) at the entry of every @manager/@accessor fn (fn_has_decorator, so it fires under @route @manager too) — a decorated op self-reports with ZERO hand-written instrumentation. Rebuilt elc self-host + the cognition engram in the worktree; ran it as the clone daemon on :8900. Proof (/api/boundary-proof, @manager, empty body, 5x): aff_boundary_ops 0->5, dharma_emits 0->5, self activation_count 1510->1513, chrono stamp advanced. Brought in feat/cognitive-architecture engram runtime+server for the build. strengthen = activation bump (not content/edge write) -> identity protection intact. Live :8742 untouched; no push, no cutover.
158 lines
7.5 KiB
C
158 lines
7.5 KiB
C
/* engram_verify.c — the VERIFIER layer. Pure compositions over engram_reason.h +
|
||
* engram_geometry.h. stdlib + libm only; READ-ONLY over its inputs; touches no
|
||
* store/index/activation. See engram_verify.h for the design and the frame contract. */
|
||
#include "engram_verify.h"
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <math.h>
|
||
|
||
/* ── small float-vector helpers (mirror engram_reason.c) ────────────────────── */
|
||
static double vdot(const float* a, const float* b, int dim) {
|
||
double s = 0; for (int i = 0; i < dim; i++) s += (double)a[i] * (double)b[i]; return s;
|
||
}
|
||
static double l2(const float* a, const float* b, int dim) {
|
||
double s = 0; for (int i = 0; i < dim; i++) { double d = (double)a[i] - (double)b[i]; s += d * d; }
|
||
return sqrt(s);
|
||
}
|
||
|
||
/* ═══════════════════════════════════════════════════════ GROUNDING ══════════ */
|
||
int engram_verify_grounding(const float* claim, int dim,
|
||
const GeoDescriptor* const* evidence, int n_evidence,
|
||
double ext_floor, double ground_threshold,
|
||
GeoGrounding* out) {
|
||
if (!claim || dim <= 0 || !evidence || n_evidence < 1 || !out) return -1;
|
||
if (!(ext_floor > 0)) ext_floor = 1.0;
|
||
if (!(ground_threshold > 0 && ground_threshold < 1)) ground_threshold = 0.5;
|
||
memset(out, 0, sizeof *out);
|
||
out->n_evidence = n_evidence;
|
||
out->best = -1;
|
||
out->nearest_centroid_l2 = INFINITY;
|
||
out->scores = malloc((size_t)n_evidence * sizeof(double));
|
||
if (!out->scores) return -1;
|
||
|
||
double best = -1;
|
||
for (int i = 0; i < n_evidence; i++) {
|
||
const GeoDescriptor* e = evidence[i];
|
||
GeoFit f;
|
||
if (!e || e->dim != dim || !e->centroid ||
|
||
engram_reason_point_fit(e, claim, ext_floor, &f) != 0) {
|
||
out->scores[i] = 0.0;
|
||
continue;
|
||
}
|
||
out->scores[i] = f.score;
|
||
double cl2 = l2(claim, e->centroid, dim);
|
||
if (cl2 < out->nearest_centroid_l2) out->nearest_centroid_l2 = cl2;
|
||
if (out->best < 0 || f.score > best) {
|
||
best = f.score;
|
||
out->best = i;
|
||
out->grounding = f.score;
|
||
out->best_distance = f.distance;
|
||
out->best_ortho = f.ortho_residual;
|
||
}
|
||
}
|
||
if (out->best < 0) { out->grounding = 0.0; out->best_distance = INFINITY; }
|
||
out->grounded = (out->grounding >= ground_threshold) ? 1 : 0;
|
||
return 0;
|
||
}
|
||
void engram_verify_grounding_free(GeoGrounding* out) {
|
||
if (!out) return;
|
||
free(out->scores); out->scores = NULL;
|
||
}
|
||
|
||
/* ═══════════════════════════════════════════════════════ CONSISTENCY ════════ */
|
||
int engram_verify_consistency(const float* claim, int dim,
|
||
const GeoDescriptor* context,
|
||
const GeoDescriptor* pole_pos, const GeoDescriptor* pole_neg,
|
||
const GeoDescriptor* forbidden,
|
||
double ext_floor, double deadzone_frac,
|
||
double forbidden_thresh, double max_distance,
|
||
GeoConsistency* out) {
|
||
if (!claim || dim <= 0 || !out) return -1;
|
||
if (!(ext_floor > 0)) ext_floor = 1.0;
|
||
if (!(deadzone_frac >= 0 && deadzone_frac < 1)) deadzone_frac = 0.10;
|
||
if (!(forbidden_thresh > 0 && forbidden_thresh < 1)) forbidden_thresh = 0.5;
|
||
memset(out, 0, sizeof *out);
|
||
out->verdict = GEO_CONSIST_OK;
|
||
out->consistency = 1.0;
|
||
|
||
int do_polarity = (pole_pos && pole_neg);
|
||
int do_distance = (max_distance > 0);
|
||
if ((do_polarity || do_distance) &&
|
||
(!context || context->dim != dim || !context->centroid)) return -1;
|
||
if (do_polarity && (pole_pos->dim != dim || pole_neg->dim != dim ||
|
||
!pole_pos->centroid || !pole_neg->centroid)) return -1;
|
||
if (forbidden && (forbidden->dim != dim || !forbidden->centroid)) return -1;
|
||
|
||
double pol_score = 1.0, geo_score = 1.0;
|
||
|
||
/* ── (a) POLARITY / negation inversion ─────────────────────────────────── */
|
||
if (do_polarity) {
|
||
/* axis p = (c_pos − c_neg); midpoint o = ½(c_pos + c_neg). */
|
||
float* p = malloc((size_t)dim * sizeof(float));
|
||
float* o = malloc((size_t)dim * sizeof(float));
|
||
if (!p || !o) { free(p); free(o); return -1; }
|
||
double pn2 = 0;
|
||
for (int i = 0; i < dim; i++) {
|
||
double dpos = (double)pole_pos->centroid[i], dneg = (double)pole_neg->centroid[i];
|
||
p[i] = (float)(dpos - dneg);
|
||
o[i] = (float)(0.5 * (dpos + dneg));
|
||
pn2 += (dpos - dneg) * (dpos - dneg);
|
||
}
|
||
double pn = sqrt(pn2);
|
||
out->polarity_separation = 0.5 * pn;
|
||
if (pn > 1e-12) {
|
||
/* signed positions along the axis (projection of (x − o) onto unit p). */
|
||
float* cdo = malloc((size_t)dim * sizeof(float)); /* claim − o */
|
||
float* rdo = malloc((size_t)dim * sizeof(float)); /* context − o */
|
||
if (!cdo || !rdo) { free(p); free(o); free(cdo); free(rdo); return -1; }
|
||
for (int i = 0; i < dim; i++) {
|
||
cdo[i] = (float)((double)claim[i] - (double)o[i]);
|
||
rdo[i] = (float)((double)context->centroid[i] - (double)o[i]);
|
||
}
|
||
double claim_side = vdot(cdo, p, dim) / pn; /* units: emb-space length */
|
||
double ref_side = vdot(rdo, p, dim) / pn;
|
||
out->polarity_claim = claim_side;
|
||
out->polarity_reference = ref_side;
|
||
double dz = deadzone_frac * out->polarity_separation; /* neutral band */
|
||
if (fabs(claim_side) > dz && fabs(ref_side) > dz &&
|
||
(claim_side > 0) != (ref_side > 0)) {
|
||
out->inverted = 1;
|
||
pol_score = 0.0; /* opposite poles ⇒ zero consistency */
|
||
} else if (fabs(claim_side) <= dz || fabs(ref_side) <= dz) {
|
||
pol_score = 0.5; /* neutral / undecided */
|
||
} else {
|
||
pol_score = 1.0; /* same pole ⇒ consistent */
|
||
}
|
||
free(cdo); free(rdo);
|
||
}
|
||
free(p); free(o);
|
||
}
|
||
|
||
/* ── (b) GEOMETRIC contradiction ───────────────────────────────────────── */
|
||
if (forbidden) {
|
||
GeoFit f;
|
||
if (engram_reason_point_fit(forbidden, claim, ext_floor, &f) == 0) {
|
||
out->forbidden_fit = f.score;
|
||
if (f.score >= forbidden_thresh) {
|
||
out->geo_violation = 1;
|
||
double g = 1.0 - f.score; if (g < 0) g = 0;
|
||
if (g < geo_score) geo_score = g;
|
||
}
|
||
}
|
||
}
|
||
if (do_distance) {
|
||
out->context_distance = l2(claim, context->centroid, dim);
|
||
if (out->context_distance > max_distance) {
|
||
out->geo_violation = 1;
|
||
geo_score = 0.0;
|
||
}
|
||
}
|
||
|
||
/* ── verdict + scalar (polarity is the headline; both flags stay visible) ─ */
|
||
out->consistency = (pol_score < geo_score) ? pol_score : geo_score;
|
||
if (out->inverted) out->verdict = GEO_CONSIST_POLARITY;
|
||
else if (out->geo_violation) out->verdict = GEO_CONSIST_GEOMETRIC;
|
||
else out->verdict = GEO_CONSIST_OK;
|
||
return 0;
|
||
}
|