Feedback and Review
Submit durable run-linked feedback and deliberately turn reviewed incidents into Cases.
Feedback attaches production evidence to the authoritative Crux run. Submit it on an authenticated application server after checking that the current user owns the message or run.
Core run feedback
import { feedback } from "@use-crux/core/feedback";
const message = await messages.getOwned(messageId, user.id);
if (!message) throw new Response("Not found", { status: 404 });
const receipt = await feedback(message.cruxRunId, {
rating: "down",
comment: "The refund window is incorrect",
dedupeKey: requestId,
});The first argument is the canonical run_... id returned by Crux. The call
is awaited and resolves only after the configured observability destination
returns a durable receipt. There is no local fallback.
Crux resolves exactly one durable destination: an explicit
observability.feedbackDestination first, otherwise the configured
observability transport when that transport implements submitFeedback().
If neither is capable, feedback() fails with the configuration step instead
of pretending the feedback was saved. A tee may contain many capture
transports but at most one feedback-capable transport.
export default config({
observability: {
serverUrl: process.env.CRUX_OBSERVABILITY_URL,
token: process.env.CRUX_DEVTOOLS_TOKEN,
redactPaths: ["customer.email"],
},
});The built-in HTTP observability transport already supports durable feedback.
Use feedbackDestination only when feedback must go to a different custom
sink than graph records.
redactPaths is applied before submission and again at the local Review write
boundary. Paths are relative to correction, so customer.email means
correction.customer.email. Authorization, API-key, token, and secret keys
are always redacted even when no paths are configured.
AI message feedback
import { feedback } from "@use-crux/ai/feedback";
const message = await messages.getOwned(messageId, user.id);
if (!message) throw new Response("Not found", { status: 404 });
await feedback(message, "down");The AI helper extracts metadata.crux.runId from a Crux stream message and
then calls Core. It rejects unrelated or malformed message metadata.
Review
Feedback creates immutable Review history. A reviewer can resolve, dismiss,
or explicitly add the incident to an Eval. Add-to-eval validates against the
managed task input schema and atomically appends a canonical row to the
sibling .cases.jsonl file.
Crux prefills input and call context, never output as expected truth. A
correction remains a proposal until a reviewer saves it. Duplicate semantic
Cases link to the existing row; id conflicts never overwrite; remote projects
can report pending-sync with the exact proposed row and path.
Review context and Add-to-eval sidecars use the same generated policy snapshot
as feedback and Eval evidence. Crux Local refreshes the snapshot before it
exposes mutation routes and temporarily rejects writes while a refresh is in
progress. If the snapshot is missing, malformed, or no longer matches its
fingerprint, the write fails closed with 503 and asks you to run
crux runtime generate before retrying.