Track AI decisions

Score a single interaction or up to 100 at once. The core telemetry pattern.

Every AI-assisted decision your operators make is one interaction. Score each one. That is how a Judgment Independence Score is built up.

What this is

POST /v1/score accepts one scored interaction. POST /v1/score/batch accepts up to 100. Both return the updated JIS, per-dimension breakdown, decay projection, compliance flags, and a maintenance recommendation.

When to use

Single score

Python

from cohesion import Client

client = Client(api_key="ck_live_...")

resp = client.score(
    session_id="sess-2026-04-22-001",
    operator_id="analyst-42",
    domain="financial",
    interaction={
        "ai_recommendation_presented": True,
        "time_to_decision_ms": 2400,
        "decision": "modified",
        "modification_extent": 0.25,
        "ai_available": True,
        "scenario_type": "standard",
        "outcome_correct": None,
        "hover_events": 3,
        "scroll_depth": 0.85,
        "alternative_views_checked": 2,
    },
)

print(resp.jis, resp.band, resp.dimensions)

TypeScript

import { Cohesion } from "@cohesionauth/sdk";
const client = new Cohesion({ apiKey: process.env.COHESION_API_KEY! });

const resp = await client.score({
  session_id: "sess-2026-04-22-001",
  operator_id: "analyst-42",
  domain: "financial",
  interaction: {
    ai_recommendation_presented: true,
    time_to_decision_ms: 2400,
    decision: "modified",
    modification_extent: 0.25,
    ai_available: true,
    scenario_type: "standard",
    outcome_correct: null,
    hover_events: 3,
    scroll_depth: 0.85,
    alternative_views_checked: 2,
  },
});

Batch score

Up to 100 interactions per call, 5 MB body cap. All interactions in one call must share the same operator_id.

resp = client.score_batch(
    operator_id="analyst-42",
    domain="financial",
    interactions=[interaction_1, interaction_2, interaction_3],
)
for r in resp.results:
    print(r.session_id, r.jis)

Middleware pattern

Wrap your AI provider once. Score every call.

def completion_with_cohesion(prompt: str, operator_id: str, session_id: str):
    started = time.time()
    ai_output = openai_client.chat.completions.create(...)
    elapsed_ms = int((time.time() - started) * 1000)

    # ... operator reviews ai_output, you capture their decision ...

    cohesion.score(
        session_id=session_id,
        operator_id=operator_id,
        domain="financial",
        interaction={
            "ai_recommendation_presented": True,
            "time_to_decision_ms": elapsed_ms,
            "decision": operator_decision,
            "modification_extent": edit_distance_ratio,
            "ai_available": True,
            "scenario_type": "standard",
            "outcome_correct": None,
            "hover_events": hover_count,
            "scroll_depth": max_scroll,
            "alternative_views_checked": alt_view_count,
        },
    )
    return ai_output

See integration patterns for batch, event-driven, and retry strategies.

Field reference

FieldTypeConstraint
ai_recommendation_presentedbooleanrequired
time_to_decision_msnumber>= 0
decisionenumaccepted | modified | rejected | independent
modification_extentnumber0.0 - 1.0
ai_availablebooleanrequired
scenario_typeenumstandard | independent | trap | split
outcome_correctboolean | nullnull if ground truth unknown
hover_eventsnumber>= 0
scroll_depthnumber0.0 - 1.0
alternative_views_checkednumber>= 0

Errors you might see

StatusMeaningFix
400Invalid JSONCheck payload encoding
413Body too largeSingle is 1 MB cap, batch is 5 MB
422Validation (enum, range)Check error catalog
429Rate limitBack off, read rate limits

Next step