> ## Documentation Index
> Fetch the complete documentation index at: https://claritylabs.inc/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Case Workflow Primitives: Evidence, Validation, and IDs

> Use shared case primitives — evidence, citations, validation, and missing info — to build durable agent workflows beyond the built-in PCE pipeline.

Case workflow primitives are the shared building blocks that power the PCE agent and the application pipeline — but they're also exported directly so you can compose them into any durable agent flow you need. Whether you're building a claims intake agent, a COI request tracker, a renewal preparation workflow, or something entirely custom, these primitives give you grounded evidence, typed validation, structured missing-info questions, and submission artifacts without having to rebuild the scaffolding yourself.

## Core Types

> **CaseEvidenceSource**
>
> Source text used for validation and citation. Carries a `sourceId`, raw text, and optional metadata like page number or document type.

> **CaseCitation**
>
> A citation with a `sourceId`, exact `quote`, optional `page` number, and optional `fieldPath`. Used to ground claims in case items back to real source text.

> **CaseValidationIssue**
>
> An `info`, `warning`, or `blocking` issue tied to an `itemId` and `fieldPath`. Blocking issues must be resolved before a submission packet is considered ready.

> **MissingInfoQuestion**
>
> A question tied to an `itemId` and optional `fieldPath`. Surfaces required information that could not be inferred from the request or evidence sources.

> **CasePacketArtifact**
>
> A generated artifact — email draft, underwriter summary, JSON packet, or validation report — associated with a submission packet.

> **CaseState**
>
> The durable workflow state object. Carries items, evidence sources, validation issues, missing-info questions, citations, and execution status.

***

## Evidence Validation

Use `validateQuotedEvidence()` to check that a citation's `quote` is genuinely present in the referenced source. Call this any time you accept a new citation — from a model, from a user, or from an external system.

```typescript theme={"system"}
import { validateQuotedEvidence } from "@claritylabs/cl-sdk";

const issues = validateQuotedEvidence({
  itemId: "change-1",
  fieldPath: "vehicle.vin",
  quote: "VIN 1FTBW2CM5RKA12345",
  citation: {
    sourceId: "email-1",
    quote: "VIN 1FTBW2CM5RKA12345",
  },
  sources,
});

if (issues.length > 0) {
  // At least one issue was found — e.g. the quote doesn't appear in the source.
  console.log(issues.map((i) => i.message));
}
```

**itemId** `string` *required*

The ID of the case item this citation belongs to.

**fieldPath** `string`

Optional dot-separated field path the citation supports (e.g. `vehicle.vin`).

**quote** `string` *required*

The text that should appear verbatim in the referenced source.

**citation** `CaseCitation` *required*

The citation object to validate. Must include `sourceId` and `quote`.

**sources** `CaseEvidenceSource[]` *required*

The evidence sources to check against. The validator looks for the `sourceId` in this list and confirms the `quote` is present in the source text.

> [!NOTE]
>
> `validateQuotedEvidence()` performs an exact substring match by default. Normalisation (whitespace collapsing, case folding) is applied before comparison so minor formatting differences don't produce false negatives.

***

## Proposal Scoring

When your workflow generates multiple competing proposals for a case item — for example, different interpretations of an ambiguous request — use `evaluateCaseProposals()` to select the best one before committing.

```typescript theme={"system"}
import { evaluateCaseProposals } from "@claritylabs/cl-sdk";

const best = evaluateCaseProposals(proposals);

// evaluateCaseProposals returns the single highest-scoring proposal, or undefined
// if all proposals have blocking validation issues.
if (best) {
  console.log(best.score);
  // {
  //   grounding: 0.92,
  //   completeness: 0.88,
  //   consistency: 1.0,
  //   determinism: 0.75,
  //   risk: 0.6,
  //   cost: 0.8,
  // }
}
```

Proposals are scored on six dimensions:

| Dimension | What it measures |
| - | - |
| `grounding` | Fraction of claims supported by evidence citations |
| `completeness` | Coverage of required fields and sub-items |
| `consistency` | Internal consistency across items in the proposal |
| `determinism` | How rule-deterministic the proposal is (vs. model-dependent) |
| `risk` | Estimated carrier or compliance risk of the proposed change |
| `cost` | Estimated token cost to execute the proposal |

> [!TIP]
>
> `evaluateCaseProposals()` internally weights `grounding` and `consistency` most heavily when selecting the best proposal. Proposals with blocking citation issues (missing quote, unknown source) are excluded entirely before scoring begins.

***

## Stable IDs

Case workflows often run as async jobs that may be retried or deduplicated. Use `stableCaseId()` to generate deterministic, hash-based identifiers so the same logical case always produces the same ID regardless of how many times it's processed.

```typescript theme={"system"}
import { stableCaseId } from "@claritylabs/cl-sdk";

const id = stableCaseId("case", [requestText, documentId, userId]);
// → "case_a3f7d1c9b..."  (deterministic hash of the inputs)
```

**prefix** `string` *required*

A short label prepended to the hash — e.g. `"case"`, `"item"`, `"packet"`. Helps you identify the ID type at a glance.

**inputs** `string[]` *required*

Array of strings that uniquely identify the entity. The hash is computed from the concatenation of these values in order.

> [!WARNING]
>
> Input order matters — `stableCaseId("case", ["a", "b"])` and `stableCaseId("case", ["b", "a"])` produce different IDs. Establish a consistent ordering convention within your application.

***

## Building a Custom Workflow

These primitives compose naturally. Here's a sketch of a claims intake workflow built from case primitives:

```typescript theme={"system"}
import {
  validateQuotedEvidence,
  evaluateCaseProposals,
  stableCaseId,
} from "@claritylabs/cl-sdk";

// 1. Generate a stable ID for this intake
const caseId = stableCaseId("claim", [claimantId, incidentDate, policyNumber]);

// 2. Collect evidence from the claim submission
const sources: CaseEvidenceSource[] = await collectEvidenceFromSubmission(
  submission,
);

// 3. Generate and validate citations for each extracted claim detail
for (const item of extractedItems) {
  const issues = validateQuotedEvidence({
    itemId: item.id,
    fieldPath: item.fieldPath,
    quote: item.citation.quote,
    citation: item.citation,
    sources,
  });
  item.validationIssues = issues;
}

// 4. Select the best competing interpretation before committing
const bestProposal = evaluateCaseProposals(competingProposals);
```

> **[PCE Overview](https://claritylabs.inc/docs/cl-sdk/pce/overview.md)**
>
> See how these primitives are assembled in the built-in Policy Change Endorsement agent.

> **[Application Pipeline](https://claritylabs.inc/docs/cl-sdk/application/overview.md)**
>
> Explore how case state patterns apply to the application processing pipeline.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.