Close the loop
An outcome recorded against a context run changes what future compiles rank first, without editing a single observation.
The agent acts outside Titen. What comes back is one small fact about the pack it was given: did any of it help? That signal is what separates a memory store that accumulates from one that gets better at choosing.
Record an outcome
await titen.feedback(ctx.context_id, {
outcome: 'useful',
claim_id: ctx.items[0]?.claim_id,
});
curl -X POST http://127.0.0.1:8787/v1/context/ctx_5aa8109e55ed41b49cb75f48868cd289/feedback \
-H "authorization: Bearer $TITEN_API_KEY" \
-H 'content-type: application/json' \
-d '{"outcome":"useful","claim_id":"claim_d5ce4657d6b947aa8ade42271b4176f5"}'
{ "data": { "feedback_id": "fb_759a0268e3a84d3b86d07b6590156714",
"context_id": "ctx_5aa8109e55ed41b49cb75f48868cd289",
"claim_id": "claim_d5ce4657d6b947aa8ade42271b4176f5",
"outcome": "useful", "recorded_at": "2026-07-30T10:47:47.575Z" },
"meta": { "request_id": "req_…", "replayed": false } }
Five outcomes
| Outcome | Effect on utility | When to send it |
|---|---|---|
used |
positive | The item made it into the prompt and the action succeeded. |
useful |
positive | The item changed what the agent did, for the better. |
irrelevant |
negative | Eligible and correct, but not about this task. |
incorrect |
negative | The claim is wrong. |
harmful |
negative | Acting on it caused damage. |
Anything else is refused rather than coerced:
{ "error": { "code": "VALIDATION_ERROR",
"message": "Field \"outcome\" must be one of: used, useful, irrelevant, incorrect, harmful." },
"meta": { "request_id": "req_e5d3a330e24343dfaf34c45d35955bbc" } }
An optional reason_code, up to 64 characters, rides along for your own evaluation queries.
incorrect and harmful are signals about a selection, not lifecycle commands: retiring a
wrong claim is a separate, authorized decision. See claim lifecycle.
claim_id decides what moves
Omit claim_id and the outcome is recorded against the whole run. Utility is counted per
claim, so only feedback that names a claim_id affects ranking. Name the claim to close the
loop; omit it when you are grading the pack as a whole.
A claim_id must be one the run actually returned. A claim that was never in the pack is a
non-disclosing 404, so feedback cannot be used to probe which claims exist:
{ "error": { "code": "NOT_FOUND", "message": "Resource was not found." },
"meta": { "request_id": "req_a4adc0eb7c74469ebe1af88bd8c00b08" } }
Retries are idempotent two ways: an Idempotency-Key header, or a client_mutation_id in
the body. Either one returns the original feedback_id with meta.replayed: true.
How utility feeds back into ranking
Positive and negative counts are read at compile time from the feedback rows themselves.
There is no cached utility score to drift out of date. The utility component works out to:
Fewer than three signals for the claim: 0.5, the neutral value.
Three or more: (net + 1) / 2, where net is (positive − negative) / total. All-positive gives 1, all-negative gives 0.
The component is weighted 0.10 in the final score, so it reorders neighbours and cannot outvote relevance or trust.
A ranking signal that moved on a single vote is a poisoning surface: anything that can call this route once could promote its own memory. Requiring three makes that attack cost more, and slows promotion for everyone equally.
Live, on the same claim, before and after three useful outcomes:
| relevance | trust | recency | utility | conflict | score | |
|---|---|---|---|---|---|---|
| before | 1 | 0.666667 | 1 | 0.5 | 1 | 0.795 |
| after | 1 | 0.666667 | 1 | 1 | 1 | 0.84 |
Its statement, trust, confidence, evidence links and status are byte-identical; only the score moved.
What feedback may never do
Rewrite observation content. Evidence is append-only, and an outcome is not evidence.
Raise trust. Trust comes from a credential's authority over its evidence, never from a popularity count.
Turn repeated opinion into fact. A claim voted useful a hundred times is still a claim, with the same trust and the same sources.
Cross a tenant, subject or visibility boundary, or delete canonical evidence on its own.
Negative feedback is kept for evaluation even after its claim is revoked, so the system can learn that a selection was bad without losing the record of what it selected.