Titentiten.devꦠꦶꦠꦺꦤ꧀
v0.1.1 · npmGitHub
DocsThe memory loopConsolidate claims

Consolidate claims

A claim is a compact conclusion that names the observations behind it — created deterministically today, with no model in the path and nothing invented.

POST /v1/consolidationsclaims:writeclaim_ + 32 hexmodel_used false

An observation says what happened. A claim says what someone concluded, and points at the evidence. Keeping the two apart is what lets a compiled context pack carry conclusions that stay checkable — every claim resolves back to observations through GET /v1/claims/:id/evidence.

Create a claim

consolidate.tstypescript
const result = await titen.consolidate('user_rama', [
  {
    kind: 'procedural',
    statement: 'Deploy smoke must pass before release.',
    confidence: 0.95,
    sources: [{ observation_id: obs.observation_id, relation: 'supports' }],
  },
]);
// result.claims[0].claim_id → "claim_f3963d7b876143f5bfc8230db2757067"
// result.model_used         → false
curl -X POST http://127.0.0.1:8787/v1/consolidations \
  -H "authorization: Bearer $TITEN_API_KEY" \
  -H 'content-type: application/json' \
  -d '{"subject_id":"user_rama","claims":[{
       "kind":"procedural","statement":"Deploy smoke must pass before release.",
       "confidence":0.95,
       "sources":[{"observation_id":"obs_ed91a2d0f66143fbba66c932494d5e64","relation":"supports"}]}]}'

One request carries up to 50 claims, each with up to 20 sources and a statement up to 4000 characters.

Kinds

The kind is a typed field, not a tag, because pack diversity reads it — at most three items of one kind enter a compiled pack.

Kind What it holds
semantic_fact A fact about the subject that is not tied to one moment.
episodic_event Something that happened, as a conclusion rather than raw evidence.
preference What the subject wants.
procedural Guidance for how work should be done.
decision A choice that was made, and therefore something a later decision can supersede.
relationship A link between two subjects, backed by evidence instead of a graph database.

Sources carry the relation

Every source names an observation and how it relates to the claim: supports, contradicts or qualifies. At least one supports is mandatory.

{ "error": { "code": "VALIDATION_ERROR",
    "message": "A claim needs at least one supporting source." },
  "meta": { "request_id": "req_e23da3bea5924b3f99cf84cf856e72ed" } }

That rule is what keeps the store from accumulating free-floating assertions.

An observation you cannot read is not reported as a permission problem — an unknown id, a foreign tenant and someone else’s private record all return the same non-disclosing 404 NOT_FOUND.

Trust and visibility are inherited, not declared

Omit trust and the claim takes the highest trust among its supporting sources. Omit visibility and it takes the narrowest visibility across all its sources, including the ones that contradict or qualify. Supplying either field can only narrow the result:

{ "error": { "code": "VALIDATION_ERROR",
    "message": "Claim trust may not exceed the trust of its supporting evidence." },
  "meta": { "request_id": "req_baae3681b26d44fe9ebd10f1b264bb3d" } }

Consolidation is therefore not a laundering step. Evidence enters with a trust ceiling from its credential, and the claim above it inherits that ceiling. confidence is separate and defaults to 0.8: it is how sure the author is, a number greater than 0 and at most 1, and it never substitutes for trust. Both appear in a compiled pack, and ranking uses them for different things.

Contradiction produces a dispute, not a winner

Attach a contradicts source and the claim commits with status: "disputed":

{ "data": { "subject_id": "user_docs_loop", "project_id": null, "model_used": false,
    "claims": [{ "claim_id": "claim_d5ce4657d6b947aa8ade42271b4176f5",
      "kind": "procedural", "status": "disputed", "trust": "verified",
      "visibility": "team", "confidence": 0.9,
      "valid_from": "2026-07-30T10:47:30.946Z", "valid_to": null,
      "evidence_ids": ["obs_c98879c3adc44f6a9b2227b821a033bd",
                       "obs_bc4984ed9153467eb41b4753c5c96d6c"] }] },
  "meta": { "request_id": "req_…", "replayed": false, "model": "disabled" } }

The claim is still retrievable. It arrives in a context pack with status: "disputed", a conflict score component of 1 and an entry in the pack’s conflicts array. Nothing was averaged, nothing was dropped, and the disagreement is the part an agent needs in order to ask a better question. Resolving it is an explicit lifecycle transition that records who decided and why.

No model is involved

model_used: false in data and model: "disabled" in meta are not placeholders for a feature that will appear later and change your response shape. They are the honest state of the deployment: consolidation today is deterministic, and no model call happens on this route.

Planned: model-driven extraction

Proposing claims from eligible observations with a model is on the roadmap, and it changes what Titen proposes, not what it accepts. Every proposed claim would still pass the same schema, scope, evidence, trust and temporal validation as a hand-written one. A model would remain unable to invent a source identifier, raise trust above its evidence, delete evidence, or resolve a dispute. Deterministic rules run first, and a model returning invalid sources commits nothing.

Next

↑↓ navigate↵ open