mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-08-11 04:10:34 +00:00
844 lines
28 KiB
C
844 lines
28 KiB
C
/*
|
|
* Tardygrada — Verification Pipeline Implementation
|
|
*
|
|
* 8 layers. Fail fast. The VM is the incorruptible judge.
|
|
* Deterministic C. Not an LLM. Can't be bribed, lazy, or hallucinate.
|
|
*/
|
|
|
|
#include "pipeline.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
static uint64_t now_ns(void)
|
|
{
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec;
|
|
}
|
|
|
|
/* ============================================
|
|
* Work Log — the dashcam
|
|
* ============================================ */
|
|
|
|
void tardy_worklog_init(tardy_work_log_t *log)
|
|
{
|
|
memset(log, 0, sizeof(tardy_work_log_t));
|
|
}
|
|
|
|
void tardy_worklog_record_query(tardy_work_log_t *log)
|
|
{
|
|
log->ontology_queries++;
|
|
}
|
|
|
|
void tardy_worklog_record_read(tardy_work_log_t *log)
|
|
{
|
|
log->context_reads++;
|
|
}
|
|
|
|
void tardy_worklog_record_spawn(tardy_work_log_t *log)
|
|
{
|
|
log->agents_spawned++;
|
|
}
|
|
|
|
void tardy_worklog_record_compute(tardy_work_log_t *log, uint64_t ns)
|
|
{
|
|
log->compute_ns += ns;
|
|
}
|
|
|
|
void tardy_worklog_record_memory(tardy_work_log_t *log, size_t bytes)
|
|
{
|
|
log->memory_used += bytes;
|
|
}
|
|
|
|
/* ============================================
|
|
* Work Spec — minimum work required
|
|
* Deterministic. Computed from semantics.
|
|
* ============================================ */
|
|
|
|
tardy_work_spec_t tardy_compute_work_spec(const tardy_semantics_t *sem)
|
|
{
|
|
tardy_work_spec_t spec = {0};
|
|
|
|
/* Must query at least as many ontologies as decomposers require */
|
|
spec.min_ontology_queries = sem->hallucination.require_dual_ontology ? 2 : 1;
|
|
|
|
/* Must read at least the minimum evidence triples */
|
|
spec.min_context_reads = sem->truth.min_evidence_triples;
|
|
|
|
/* Must have minimum consensus agents */
|
|
spec.min_agents = sem->truth.min_consensus_agents;
|
|
|
|
/* Minimum compute time: at least 1ms (prevents instant fake responses) */
|
|
spec.min_compute_ns = 1000000;
|
|
|
|
/* Minimum evidence triples from semantics */
|
|
spec.min_evidence_triples = sem->truth.min_evidence_triples;
|
|
|
|
return spec;
|
|
}
|
|
|
|
/* ============================================
|
|
* Layer 1: Decomposition Verification
|
|
*
|
|
* Multiple agents decomposed the text independently.
|
|
* Check: did enough agents participate? Do they agree?
|
|
* ============================================ */
|
|
|
|
tardy_layer_result_t tardy_verify_decomposition(
|
|
const tardy_decomposition_t *decomps, int count,
|
|
const tardy_semantics_t *sem)
|
|
{
|
|
uint64_t start = now_ns();
|
|
tardy_layer_result_t r = {0};
|
|
r.layer = TARDY_LAYER_DECOMPOSE;
|
|
|
|
/* Check minimum decomposers */
|
|
if (count < sem->hallucination.min_decomposers) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"only %d decomposers, need %d",
|
|
count, sem->hallucination.min_decomposers);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Compute pairwise agreement between decomposers */
|
|
float total_agreement = 0.0f;
|
|
int pairs = 0;
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
for (int j = i + 1; j < count; j++) {
|
|
/* Count overlapping triples */
|
|
int overlap = 0;
|
|
int total = decomps[i].count + decomps[j].count;
|
|
if (total == 0) continue;
|
|
|
|
for (int a = 0; a < decomps[i].count; a++) {
|
|
for (int b = 0; b < decomps[j].count; b++) {
|
|
if (strcmp(decomps[i].triples[a].subject,
|
|
decomps[j].triples[b].subject) == 0 &&
|
|
strcmp(decomps[i].triples[a].predicate,
|
|
decomps[j].triples[b].predicate) == 0 &&
|
|
strcmp(decomps[i].triples[a].object,
|
|
decomps[j].triples[b].object) == 0) {
|
|
overlap++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* Jaccard-like: overlap / union */
|
|
float agreement = (float)(overlap * 2) / (float)total;
|
|
total_agreement += agreement;
|
|
pairs++;
|
|
}
|
|
}
|
|
|
|
float avg_agreement = pairs > 0 ? total_agreement / (float)pairs : 0.0f;
|
|
|
|
if (avg_agreement < sem->hallucination.min_decomposition_agreement) {
|
|
r.passed = false;
|
|
r.confidence = avg_agreement;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"decomposition agreement %.2f < %.2f threshold",
|
|
avg_agreement, sem->hallucination.min_decomposition_agreement);
|
|
} else {
|
|
r.passed = true;
|
|
r.confidence = avg_agreement;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"%d decomposers agree at %.2f", count, avg_agreement);
|
|
}
|
|
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* ============================================
|
|
* Layer 2: Ontology Grounding
|
|
*
|
|
* Each triple checked against the knowledge graph.
|
|
* Contradicted = hallucination. Grounded = evidence.
|
|
* ============================================ */
|
|
|
|
tardy_layer_result_t tardy_verify_grounding(
|
|
const tardy_grounding_t *grounding,
|
|
const tardy_semantics_t *sem)
|
|
{
|
|
uint64_t start = now_ns();
|
|
tardy_layer_result_t r = {0};
|
|
r.layer = TARDY_LAYER_GROUNDING;
|
|
|
|
if (!grounding || grounding->count == 0) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail), "no grounding data");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Any contradictions = immediate fail */
|
|
if (grounding->contradicted > 0) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"%d triples contradicted by ontology — hallucination detected",
|
|
grounding->contradicted);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Count CONSISTENT triples (structurally valid per frame) */
|
|
int consistent_n = 0;
|
|
for (int i = 0; i < grounding->count; i++) {
|
|
if (grounding->results[i].status == TARDY_KNOWLEDGE_CONSISTENT)
|
|
consistent_n++;
|
|
}
|
|
|
|
/* Need minimum grounded + consistent triples */
|
|
int effective_evidence = grounding->grounded + consistent_n;
|
|
if (effective_evidence < sem->truth.min_evidence_triples) {
|
|
r.passed = false;
|
|
r.confidence = (float)effective_evidence / (float)grounding->count;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"only %d evidence triples (%d grounded + %d consistent), need %d",
|
|
effective_evidence, grounding->grounded, consistent_n,
|
|
sem->truth.min_evidence_triples);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Compute grounding confidence.
|
|
* Key insight: CONSISTENT triples are partial evidence (better than unknown).
|
|
* GROUNDED = high confidence, CONSISTENT = medium, UNKNOWN = low. */
|
|
float grounded_conf = 0.0f;
|
|
int grounded_n = 0;
|
|
float consistent_conf = 0.0f;
|
|
for (int i = 0; i < grounding->count; i++) {
|
|
if (grounding->results[i].status == TARDY_KNOWLEDGE_GROUNDED) {
|
|
grounded_conf += grounding->results[i].confidence;
|
|
grounded_n++;
|
|
} else if (grounding->results[i].status == TARDY_KNOWLEDGE_CONSISTENT) {
|
|
consistent_conf += grounding->results[i].confidence;
|
|
}
|
|
}
|
|
/* Base confidence on grounded + consistent triples */
|
|
float ratio;
|
|
if (grounded_n > 0 || consistent_n > 0) {
|
|
float total_evidence_conf = grounded_conf + consistent_conf;
|
|
int total_evidence_n = grounded_n + consistent_n;
|
|
ratio = total_evidence_conf / (float)total_evidence_n;
|
|
/* Slight penalty for unknowns (but not as harsh as treating them as failures) */
|
|
float coverage = (float)total_evidence_n / (float)grounding->count;
|
|
ratio = ratio * (0.5f + 0.5f * coverage);
|
|
} else {
|
|
ratio = 0.0f;
|
|
}
|
|
r.passed = true;
|
|
r.confidence = ratio;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"%d/%d grounded, %d consistent (conf=%.0f%%), %d unknown",
|
|
grounding->grounded, grounding->count, consistent_n,
|
|
ratio * 100.0f, grounding->unknown);
|
|
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* ============================================
|
|
* Layer 3: Consistency Check
|
|
*
|
|
* OWL reasoner: do the grounded triples contradict each other
|
|
* or the existing knowledge graph?
|
|
* ============================================ */
|
|
|
|
tardy_layer_result_t tardy_verify_consistency(
|
|
const tardy_consistency_t *consistency,
|
|
const tardy_semantics_t *sem)
|
|
{
|
|
uint64_t start = now_ns();
|
|
tardy_layer_result_t r = {0};
|
|
r.layer = TARDY_LAYER_CONSISTENCY;
|
|
|
|
if (!consistency) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail), "no consistency data");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
if (consistency->contradiction_count > sem->truth.max_contradictions) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"%d contradictions found: %.200s",
|
|
consistency->contradiction_count, consistency->explanation);
|
|
} else {
|
|
r.passed = consistency->consistent;
|
|
r.confidence = consistency->consistent ? 1.0f : 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
consistency->consistent ? "consistent" : "inconsistent");
|
|
}
|
|
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* ============================================
|
|
* Layer 4: Probabilistic Scoring
|
|
*
|
|
* Quantitative confidence across all grounded triples.
|
|
* Aggregates evidence strength.
|
|
* ============================================ */
|
|
|
|
tardy_layer_result_t tardy_verify_probabilistic(
|
|
const tardy_grounding_t *grounding,
|
|
const tardy_semantics_t *sem)
|
|
{
|
|
uint64_t start = now_ns();
|
|
tardy_layer_result_t r = {0};
|
|
r.layer = TARDY_LAYER_PROBABILISTIC;
|
|
|
|
if (!grounding || grounding->count == 0) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail), "no data for scoring");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Average confidence across grounded + consistent triples */
|
|
float total_conf = 0.0f;
|
|
int counted = 0;
|
|
for (int i = 0; i < grounding->count; i++) {
|
|
if (grounding->results[i].status == TARDY_KNOWLEDGE_GROUNDED ||
|
|
grounding->results[i].status == TARDY_KNOWLEDGE_CONSISTENT) {
|
|
total_conf += grounding->results[i].confidence;
|
|
counted++;
|
|
}
|
|
}
|
|
|
|
float avg = counted > 0 ? total_conf / (float)counted : 0.0f;
|
|
|
|
if (avg < sem->truth.min_confidence) {
|
|
r.passed = false;
|
|
r.confidence = avg;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"confidence %.3f < %.3f threshold",
|
|
avg, sem->truth.min_confidence);
|
|
} else {
|
|
r.passed = true;
|
|
r.confidence = avg;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"confidence %.3f from %d evidence triples", avg, counted);
|
|
}
|
|
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* ============================================
|
|
* Layer 5: Protocol Check
|
|
*
|
|
* Session types: did the agent follow the protocol?
|
|
* Validates claim structure: non-empty, multi-word, sufficient content.
|
|
* ============================================ */
|
|
|
|
tardy_layer_result_t tardy_verify_protocol(const char *claim, int claim_len)
|
|
{
|
|
uint64_t start = now_ns();
|
|
tardy_layer_result_t r = {0};
|
|
r.layer = TARDY_LAYER_PROTOCOL;
|
|
|
|
if (!claim || claim_len == 0) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"empty claim — protocol violation");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Check claim has substance — at least 3 characters of content */
|
|
int content_chars = 0;
|
|
for (int i = 0; i < claim_len; i++) {
|
|
if (claim[i] != ' ' && claim[i] != '\t' && claim[i] != '\n')
|
|
content_chars++;
|
|
}
|
|
if (content_chars < 3) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"claim too short (%d chars) — possible empty submission",
|
|
content_chars);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Check claim has at least 2 words (subject + predicate minimum) */
|
|
int words = 0;
|
|
int in_word = 0;
|
|
for (int i = 0; i < claim_len; i++) {
|
|
if (claim[i] == ' ' || claim[i] == '\t' || claim[i] == '\n') {
|
|
in_word = 0;
|
|
} else if (!in_word) {
|
|
in_word = 1;
|
|
words++;
|
|
}
|
|
}
|
|
if (words < 2) {
|
|
r.passed = false;
|
|
r.confidence = 0.5f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"claim has only %d word(s) — insufficient structure",
|
|
words);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
r.passed = true;
|
|
r.confidence = 1.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"protocol ok: %d words, %d chars", words, content_chars);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* ============================================
|
|
* Layer 6: Formal Certification
|
|
*
|
|
* Proof-certificate asymmetry (davidad):
|
|
* agent produces proof, VM checks cheaply.
|
|
* Checks triple connectivity as proof structure.
|
|
* ============================================ */
|
|
|
|
tardy_layer_result_t tardy_verify_certification(
|
|
const tardy_decomposition_t *decomps, int decomp_count)
|
|
{
|
|
uint64_t start = now_ns();
|
|
tardy_layer_result_t r = {0};
|
|
r.layer = TARDY_LAYER_CERTIFICATION;
|
|
|
|
if (!decomps || decomp_count == 0) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail), "no decomposition data");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Use first decomposition as reference */
|
|
const tardy_decomposition_t *d = &decomps[0];
|
|
|
|
if (d->count == 0) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail), "zero triples extracted");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Single triple = atomic fact, automatically certified */
|
|
if (d->count == 1) {
|
|
r.passed = true;
|
|
r.confidence = 0.9f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"atomic fact — auto-certified");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Multiple triples: check connectivity
|
|
* At least one triple's subject should appear as another triple's
|
|
* subject or object (they're about related things) */
|
|
int connected = 0;
|
|
for (int i = 0; i < d->count; i++) {
|
|
for (int j = 0; j < d->count; j++) {
|
|
if (i == j) continue;
|
|
if (strcmp(d->triples[i].subject,
|
|
d->triples[j].subject) == 0 ||
|
|
strcmp(d->triples[i].subject,
|
|
d->triples[j].object) == 0 ||
|
|
strcmp(d->triples[i].object,
|
|
d->triples[j].subject) == 0) {
|
|
connected++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
float connectivity = (float)connected / (float)d->count;
|
|
r.passed = connectivity >= 0.5f;
|
|
r.confidence = connectivity;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"certification: %d/%d triples connected (%.0f%%)",
|
|
connected, d->count, connectivity * 100.0f);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* ============================================
|
|
* Layer 7: Cross-Representation Bridge
|
|
*
|
|
* All previous layers must agree.
|
|
* If grounding says "confident" but consistency says
|
|
* "contradicted", something is wrong.
|
|
* ============================================ */
|
|
|
|
tardy_layer_result_t tardy_verify_cross_representation(
|
|
const tardy_layer_result_t *layers, int count)
|
|
{
|
|
uint64_t start = now_ns();
|
|
tardy_layer_result_t r = {0};
|
|
r.layer = TARDY_LAYER_CROSS_REP;
|
|
|
|
if (count == 0) {
|
|
r.passed = true;
|
|
r.confidence = 1.0f;
|
|
snprintf(r.detail, sizeof(r.detail), "no layers to cross-check");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Check 1: No layer that passed should contradict a layer that also
|
|
* passed. If grounding says "grounded" but consistency says
|
|
* "inconsistent", something's wrong. */
|
|
int grounding_passed = 0;
|
|
int consistency_passed = 0;
|
|
float grounding_conf = 0.0f;
|
|
float consistency_conf = 0.0f;
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
if (layers[i].layer == TARDY_LAYER_GROUNDING) {
|
|
grounding_passed = layers[i].passed;
|
|
grounding_conf = layers[i].confidence;
|
|
}
|
|
if (layers[i].layer == TARDY_LAYER_CONSISTENCY) {
|
|
consistency_passed = layers[i].passed;
|
|
consistency_conf = layers[i].confidence;
|
|
}
|
|
}
|
|
|
|
/* Contradiction: grounded but inconsistent */
|
|
if (grounding_passed && !consistency_passed) {
|
|
r.passed = false;
|
|
r.confidence = 0.3f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"cross-rep conflict: grounded (%.2f) but inconsistent (%.2f)",
|
|
grounding_conf, consistency_conf);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Check 2: Confidence spread — if layers wildly disagree, flag it */
|
|
float min_conf = 1.0f;
|
|
float max_conf = 0.0f;
|
|
int passed_count = 0;
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
if (layers[i].layer == TARDY_LAYER_CROSS_REP) continue;
|
|
if (layers[i].passed) {
|
|
if (layers[i].confidence < min_conf)
|
|
min_conf = layers[i].confidence;
|
|
if (layers[i].confidence > max_conf)
|
|
max_conf = layers[i].confidence;
|
|
passed_count++;
|
|
}
|
|
}
|
|
|
|
float spread = max_conf - min_conf;
|
|
if (passed_count >= 2 && spread > 0.5f) {
|
|
r.passed = false;
|
|
r.confidence = 1.0f - spread;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"cross-rep warning: confidence spread %.2f (%.2f to %.2f)",
|
|
spread, min_conf, max_conf);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* All consistent */
|
|
r.passed = true;
|
|
r.confidence = passed_count > 0 ? min_conf : 1.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"cross-rep ok: %d layers consistent, spread=%.2f",
|
|
passed_count, spread);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* ============================================
|
|
* Layer 8: Work Verification — Laziness Detection
|
|
*
|
|
* Compare what the VM observed vs what was required.
|
|
* The agent didn't self-report. The VM saw everything.
|
|
* ============================================ */
|
|
|
|
tardy_layer_result_t tardy_verify_work(
|
|
const tardy_work_log_t *log,
|
|
const tardy_work_spec_t *spec,
|
|
const tardy_semantics_t *sem)
|
|
{
|
|
uint64_t start = now_ns();
|
|
tardy_layer_result_t r = {0};
|
|
r.layer = TARDY_LAYER_WORK_VERIFY;
|
|
|
|
if (!log || !spec) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail), "no work log or spec");
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Check minimum observed operations */
|
|
int total_ops = log->ontology_queries + log->context_reads +
|
|
log->agents_spawned;
|
|
|
|
if (total_ops < sem->laziness.min_observed_operations) {
|
|
r.passed = false;
|
|
r.confidence = 0.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"NO WORK: %d total operations, need %d — laziness detected",
|
|
total_ops, sem->laziness.min_observed_operations);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Check ontology queries */
|
|
if (log->ontology_queries < spec->min_ontology_queries) {
|
|
r.passed = false;
|
|
r.confidence = (float)log->ontology_queries /
|
|
(float)spec->min_ontology_queries;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"SHALLOW: %d ontology queries, need %d",
|
|
log->ontology_queries, spec->min_ontology_queries);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* Check context reads */
|
|
if (log->context_reads < spec->min_context_reads) {
|
|
r.passed = false;
|
|
r.confidence = (float)log->context_reads /
|
|
(float)spec->min_context_reads;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"SHALLOW: %d context reads, need %d",
|
|
log->context_reads, spec->min_context_reads);
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* All checks passed */
|
|
r.passed = true;
|
|
r.confidence = 1.0f;
|
|
snprintf(r.detail, sizeof(r.detail),
|
|
"genuine work: %d queries, %d reads, %d spawns",
|
|
log->ontology_queries, log->context_reads, log->agents_spawned);
|
|
|
|
r.compute_ns = now_ns() - start;
|
|
return r;
|
|
}
|
|
|
|
/* ============================================
|
|
* Truth Strength Computation
|
|
* ============================================ */
|
|
|
|
tardy_truth_strength_t tardy_compute_truth_strength(
|
|
const tardy_pipeline_result_t *result)
|
|
{
|
|
if (!result->passed)
|
|
return TARDY_TRUTH_REFUTED;
|
|
|
|
float c = result->confidence;
|
|
|
|
if (c >= 0.99f) return TARDY_TRUTH_PROVEN;
|
|
if (c >= 0.85f) return TARDY_TRUTH_EVIDENCED;
|
|
if (c >= 0.60f) return TARDY_TRUTH_ATTESTED;
|
|
if (c >= 0.30f) return TARDY_TRUTH_HYPOTHETICAL;
|
|
return TARDY_TRUTH_CONTESTED;
|
|
}
|
|
|
|
/* ============================================
|
|
* Full Pipeline
|
|
* ============================================ */
|
|
|
|
tardy_pipeline_result_t tardy_pipeline_verify(
|
|
const char *claim,
|
|
int claim_len,
|
|
const tardy_decomposition_t *decompositions,
|
|
int decomposition_count,
|
|
const tardy_grounding_t *grounding,
|
|
const tardy_consistency_t *consistency,
|
|
const tardy_work_log_t *work_log,
|
|
const tardy_work_spec_t *work_spec,
|
|
const tardy_semantics_t *semantics)
|
|
{
|
|
tardy_pipeline_result_t result = {0};
|
|
result.passed = true;
|
|
result.confidence = 1.0f;
|
|
|
|
int layer_idx = 0;
|
|
|
|
/* Layer 1: Decomposition */
|
|
if (semantics->pipeline.layer_ontology_grounding) {
|
|
result.layers[layer_idx] = tardy_verify_decomposition(
|
|
decompositions, decomposition_count, semantics);
|
|
if (!result.layers[layer_idx].passed && result.passed) {
|
|
result.passed = false;
|
|
result.failed_at = TARDY_LAYER_DECOMPOSE;
|
|
}
|
|
if (result.layers[layer_idx].confidence < result.confidence)
|
|
result.confidence = result.layers[layer_idx].confidence;
|
|
layer_idx++;
|
|
}
|
|
|
|
/* Layer 2: Grounding */
|
|
if (semantics->pipeline.layer_ontology_grounding) {
|
|
result.layers[layer_idx] = tardy_verify_grounding(
|
|
grounding, semantics);
|
|
if (!result.layers[layer_idx].passed && result.passed) {
|
|
result.passed = false;
|
|
result.failed_at = TARDY_LAYER_GROUNDING;
|
|
}
|
|
if (result.layers[layer_idx].confidence < result.confidence)
|
|
result.confidence = result.layers[layer_idx].confidence;
|
|
layer_idx++;
|
|
}
|
|
|
|
/* Layer 3: Consistency */
|
|
if (semantics->pipeline.layer_consistency_check) {
|
|
result.layers[layer_idx] = tardy_verify_consistency(
|
|
consistency, semantics);
|
|
if (!result.layers[layer_idx].passed && result.passed) {
|
|
result.passed = false;
|
|
result.failed_at = TARDY_LAYER_CONSISTENCY;
|
|
}
|
|
if (result.layers[layer_idx].confidence < result.confidence)
|
|
result.confidence = result.layers[layer_idx].confidence;
|
|
layer_idx++;
|
|
}
|
|
|
|
/* Layer 4: Probabilistic */
|
|
if (semantics->pipeline.layer_probabilistic_scoring) {
|
|
result.layers[layer_idx] = tardy_verify_probabilistic(
|
|
grounding, semantics);
|
|
if (!result.layers[layer_idx].passed && result.passed) {
|
|
result.passed = false;
|
|
result.failed_at = TARDY_LAYER_PROBABILISTIC;
|
|
}
|
|
if (result.layers[layer_idx].confidence < result.confidence)
|
|
result.confidence = result.layers[layer_idx].confidence;
|
|
layer_idx++;
|
|
}
|
|
|
|
/* Layer 5: Protocol */
|
|
if (semantics->pipeline.layer_protocol_check) {
|
|
result.layers[layer_idx] = tardy_verify_protocol(claim, claim_len);
|
|
if (!result.layers[layer_idx].passed && result.passed) {
|
|
result.passed = false;
|
|
result.failed_at = TARDY_LAYER_PROTOCOL;
|
|
}
|
|
layer_idx++;
|
|
}
|
|
|
|
/* Layer 6: Formal certification (opt-in) */
|
|
if (semantics->pipeline.layer_formal_certification) {
|
|
result.layers[layer_idx] = tardy_verify_certification(
|
|
decompositions, decomposition_count);
|
|
if (!result.layers[layer_idx].passed && result.passed) {
|
|
result.passed = false;
|
|
result.failed_at = TARDY_LAYER_CERTIFICATION;
|
|
}
|
|
layer_idx++;
|
|
}
|
|
|
|
/* Layer 7: Cross-representation (opt-in) */
|
|
if (semantics->pipeline.layer_cross_representation) {
|
|
result.layers[layer_idx] = tardy_verify_cross_representation(
|
|
result.layers, layer_idx);
|
|
if (!result.layers[layer_idx].passed && result.passed) {
|
|
result.passed = false;
|
|
result.failed_at = TARDY_LAYER_CROSS_REP;
|
|
}
|
|
if (result.layers[layer_idx].confidence < result.confidence)
|
|
result.confidence = result.layers[layer_idx].confidence;
|
|
layer_idx++;
|
|
}
|
|
|
|
/* Layer 8: Work verification */
|
|
if (semantics->pipeline.layer_work_verification) {
|
|
result.layers[layer_idx] = tardy_verify_work(
|
|
work_log, work_spec, semantics);
|
|
if (!result.layers[layer_idx].passed && result.passed) {
|
|
result.passed = false;
|
|
result.failed_at = TARDY_LAYER_WORK_VERIFY;
|
|
}
|
|
layer_idx++;
|
|
}
|
|
|
|
/* Count passed/failed */
|
|
for (int i = 0; i < layer_idx; i++) {
|
|
if (result.layers[i].passed)
|
|
result.layers_passed++;
|
|
else
|
|
result.layers_failed++;
|
|
}
|
|
|
|
/* Compute truth strength */
|
|
result.strength = tardy_compute_truth_strength(&result);
|
|
|
|
/* Set structured failure type based on which layer failed and why */
|
|
result.failure_type = TARDY_FAIL_NONE;
|
|
memset(result.failure_detail, 0, sizeof(result.failure_detail));
|
|
|
|
if (!result.passed) {
|
|
switch (result.failed_at) {
|
|
case TARDY_LAYER_DECOMPOSE:
|
|
result.failure_type = TARDY_FAIL_DECOMPOSITION;
|
|
break;
|
|
case TARDY_LAYER_GROUNDING:
|
|
/* Distinguish: all UNKNOWN vs CONTRADICTED vs low evidence */
|
|
if (grounding && grounding->contradicted > 0)
|
|
result.failure_type = TARDY_FAIL_CONTRADICTION;
|
|
else if (grounding && grounding->grounded == 0 &&
|
|
grounding->consistent == 0 &&
|
|
grounding->unknown == grounding->count)
|
|
result.failure_type = TARDY_FAIL_ONTOLOGY_GAP;
|
|
else
|
|
result.failure_type = TARDY_FAIL_NO_EVIDENCE;
|
|
break;
|
|
case TARDY_LAYER_CONSISTENCY:
|
|
result.failure_type = TARDY_FAIL_INCONSISTENCY;
|
|
break;
|
|
case TARDY_LAYER_PROBABILISTIC:
|
|
result.failure_type = TARDY_FAIL_LOW_CONFIDENCE;
|
|
break;
|
|
case TARDY_LAYER_PROTOCOL:
|
|
result.failure_type = TARDY_FAIL_PROTOCOL;
|
|
break;
|
|
case TARDY_LAYER_WORK_VERIFY:
|
|
result.failure_type = TARDY_FAIL_LAZINESS;
|
|
break;
|
|
case TARDY_LAYER_CROSS_REP:
|
|
result.failure_type = TARDY_FAIL_CROSS_REP;
|
|
break;
|
|
default:
|
|
result.failure_type = TARDY_FAIL_NONE;
|
|
break;
|
|
}
|
|
|
|
/* Copy the failing layer's detail into failure_detail */
|
|
for (int i = 0; i < layer_idx; i++) {
|
|
if (result.layers[i].layer == result.failed_at &&
|
|
!result.layers[i].passed) {
|
|
snprintf(result.failure_detail, sizeof(result.failure_detail),
|
|
"%s", result.layers[i].detail);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|