Skip to content

Generic Evaluation API V1

Die Generic Evaluation API gleicht temporäre symbolische Signale deterministisch mit vertrauensfähigen Evaluationsregeln im bestehenden FragmentStore ab.

POST https://lenny-api.mycubeserver.com/v1/evaluations

Die Schnittstelle ist generisch. Sie kann beispielsweise Interaktionen, technische Zustände, Risiken, Prozesse, Qualität oder Maschinenzustände auswerten. Sie enthält keine emotionsspezifische Logik.

Funktionsgrenze

Der Ablauf ist fest:

  1. Request validieren.
  2. Domain-Namespace evaluation:<domain> im FragmentStore lesen.
  3. Nur Regeln verwenden, die den bestehenden Trust-/Stability-Gate bestehen.
  4. Alle requires-Terme exakt abgleichen.
  5. Regeln mit zutreffendem excludes blockieren.
  6. Vertrauensfähige explizite contrast-Relationen prüfen.
  7. concludes-Outcomes exakt filtern.
  8. Ergebnisse und Proof deterministisch sortieren.

Die Evaluation:

  • schreibt keine Fragmente, Kandidaten, Patterns oder Erinnerungen;
  • verändert keine Support-, Resonanz- oder Stability-Werte;
  • ruft kein LLM, Ollama oder einen externen Dienst auf;
  • interpretiert keine Rohtexte, Synonyme, Negationen oder Ähnlichkeiten;
  • verwendet requested_outcomes nur als exakten Filter.

Keine Regeln aus Request-Daten

Signale existieren nur für die Dauer des Requests. Sie werden nicht gespeichert und erzeugen keine neuen Regeln oder Kandidaten.

Authentifizierung

Der Endpoint erfordert einen gültigen Bearer-Key:

Authorization: Bearer sk-lenny-DEIN-KEY

Fehlende oder ungültige Keys ergeben HTTP 401. Der Endpoint verwendet dasselbe benutzerbezogene Rate-Limit wie die bestehende API; eine Überschreitung ergibt HTTP 429.

Request

{
  "domain": "interaction_analysis",
  "evaluation_type": "hypothesis_match",
  "signals": [
    {
      "id": "signal-1",
      "term": "friction:high",
      "evidence_refs": ["feature:friction"]
    },
    {
      "id": "signal-2",
      "term": "certainty:low",
      "evidence_refs": ["feature:certainty"]
    },
    {
      "id": "signal-3",
      "term": "engagement:medium_or_high",
      "evidence_refs": ["feature:engagement"]
    }
  ],
  "requested_outcomes": [
    "hypothesis:confusion",
    "hypothesis:frustration"
  ]
}

Request-Felder

Feld Pflicht Grenze Funktion
domain ja 64 Zeichen Wird getrimmt und kleingeschrieben; bestimmt evaluation:<domain>
evaluation_type ja fester Wert In V1 ausschließlich hypothesis_match
signals ja 1 bis 200 Temporäre symbolische Signale
signals[].id ja 128 Zeichen Innerhalb des Requests eindeutig
signals[].term ja 256 Zeichen Exakter symbolischer Term wie temperature:high
signals[].evidence_refs nein maximal 20 Symbolische Belegreferenzen; keine Metadatenobjekte
requested_outcomes nein 1 bis 200 Exakte Outcome-Filter; erzeugen keine Outcomes

Unbekannte Felder, Rohtextfelder, numerische Signalwerte, doppelte Signal-IDs und mehr als 200 Signale werden mit HTTP 422 abgelehnt. Die maximale Requestgröße beträgt 1 MiB; größere Requests ergeben HTTP 413.

Listenreihenfolgen bleiben Bestandteil des kanonischen Request-Hashes. Objektschlüssel werden für den Hash sortiert.

Erfolgreiche Response

{
  "status": "evaluated",
  "engine_version": "evaluation-v1",
  "request_hash": "sha256-hexwert",
  "results": [
    {
      "outcome": "hypothesis:confusion",
      "rule_fragment_id": "frag:evaluation:interaction-confusion-v1",
      "support_floor": 0.63,
      "matched_signal_ids": ["signal-1", "signal-2", "signal-3"],
      "evidence_refs": [
        "feature:certainty",
        "feature:engagement",
        "feature:friction"
      ],
      "proof": {
        "requires": [
          {"signal_id": "signal-2", "term": "certainty:low"},
          {"signal_id": "signal-3", "term": "engagement:medium_or_high"},
          {"signal_id": "signal-1", "term": "friction:high"}
        ],
        "conclusion_relation": {
          "from": "interaction.confusion.v1",
          "relation": "concludes",
          "to": "hypothesis:confusion"
        },
        "fragment_ids": ["frag:evaluation:interaction-confusion-v1"]
      }
    }
  ],
  "unknown_reasons": []
}

support_floor wird nur aus einem real gespeicherten numerischen stability_score übernommen. Der Wert wird nicht umgerechnet und ist keine Wahrscheinlichkeit. Ohne gespeicherten Wert ist das Feld null.

Unknown-Response

Wenn kein Ergebnis belegbar ist, bleibt HTTP 200; der fachliche Status lautet unknown:

{
  "status": "unknown",
  "engine_version": "evaluation-v1",
  "request_hash": "sha256-hexwert",
  "results": [],
  "unknown_reasons": ["domain_not_found"]
}

Mögliche Gründe:

Grund Bedeutung
insufficient_signals Mindestens ein erforderlicher Term fehlt
no_eligible_rule Keine strukturell ausführbare Regel passt
rule_below_trust_gate Regeln existieren, bestehen aber den bestehenden Trust-Gate nicht
contradictory_signals Eine vertrauensfähige explizite contrast-Relation trifft zu
requested_outcome_not_supported Passende Regeln schließen keines der angefragten Outcomes
domain_not_found Der Namespace evaluation:<domain> existiert nicht

Es werden keine freien Erklärungstexte oder geratenen Outcomes erzeugt.

curl

export LENNY_API_KEY="sk-lenny-DEIN-KEY"

curl --fail-with-body -sS \
  -X POST "https://lenny-api.mycubeserver.com/v1/evaluations" \
  -H "Authorization: Bearer ${LENNY_API_KEY}" \
  -H "Content-Type: application/json" \
  --data-binary @evaluation-request.json \
  | python3 -m json.tool

Python

import json
import os
import urllib.request

payload = {
    "domain": "operations",
    "evaluation_type": "hypothesis_match",
    "signals": [
        {"id": "sensor-1", "term": "temperature:high", "evidence_refs": []},
        {"id": "sensor-2", "term": "pressure:high", "evidence_refs": []},
    ],
    "requested_outcomes": ["action:inspection_required"],
}

request = urllib.request.Request(
    "https://lenny-api.mycubeserver.com/v1/evaluations",
    data=json.dumps(payload, separators=(",", ":")).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {os.environ['LENNY_API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)

with urllib.request.urlopen(request, timeout=30) as response:
    result = json.load(response)

print(result["status"])
print(result["results"])

Regelrepräsentation

Regeln sind normale Fragmente im bestehenden FragmentStore. V1 interpretiert ausschließlich:

  • requires: jeder Term muss exakt in den Request-Signalen vorhanden sein;
  • excludes: ein vorhandener Term blockiert die Regel;
  • concludes: erzeugt ein Outcome, sofern die Regel vollständig passt.

Ein Namespace oder eine Regel-ID erteilt keine Sonderfreigabe. Nur der unveränderte bestehende Trust-/Stability-Pfad entscheidet, ob eine gespeicherte Regel ausgeführt werden darf. Das Anlegen oder Freigeben produktiver Regeln ist ein separater administrativer Vorgang und nicht Teil dieses Endpoints.

Regeln trainieren

Evaluation-Regeln werden nicht durch Evaluation-Requests gelernt. Sie muessen als Kandidaten-Fragmente in den FragmentStore importiert werden, z.B. ueber den Admin-Endpunkt POST /v1/admin/fragment_training.

Auch dieser Import setzt keine Wahrheit:

status = raw
truth_status = candidate_only
answer_allowed = false
promotion_allowed = false

Eine Regel wird erst ausgefuehrt, wenn der bestehende Trust-/Stability-Gate sie traegt. Fuer den Betrieb ist die interne Admin-Doku "Fragment Training API V1" massgeblich.