Response feedback
The automatic mode does not trust itself until people have told it, incident by
incident, whether it was right. That is what response feedback is: one verdict
per incident, given by a person with the Response role, counted into the
tenant’s calibration gate. Until
the gate opens the producer only proposes; with it open and auto_enabled: true it executes. The verdicts are also the way back — a false_positive
releases what the incident holds.
Feedback exists since 0.32. It is not the same thing as model feedback, which rates a model result and never releases anything.
The three verdicts
Section titled “The three verdicts”| Verdict | Meaning | Counted as | Weight | Effect on held actions |
|---|---|---|---|---|
true_positive |
The incident was real; blocking was, or would have been, right | block_appropriate when an action of the incident was held, missed_should_block when none was |
+5, +10 | None |
false_positive |
The incident was not what it looked like; nothing should have been blocked | release_expected |
−15 | Releases every held action of the incident, cancels a pending automatic one, closes the incident to the producer for good |
unknown |
Cannot say | — | 0 | None |
The verdicts are the analyst’s words; the counted as column is the
specification’s outcome vocabulary they are mapped onto, and the weight is the
spec’s. A true_positive confirms and releases nothing. unknown is stored
and reported, but has no weight: it can neither open nor close the gate, and it
does not count towards the label minimum.
What a false_positive does, precisely. Every executed, reconciling
or executing action of the incident moves to rollback_requested — the
same path as the Release button, standby node first, rolled_back only once
every node confirmed the absence. An automatic action that was approved but
not yet applied is cancelled. The response tells you which ids it touched
(released_action_ids, cancelled_action_ids) and never claims the rollback
already happened. From then on the producer never creates an action for that
incident again, and an automatic action that reaches apply time with the
verdict on record fails with the reason.
Why the responder role. A verdict that releases a quarantine is a
response decision, and the specification gives release to the responder. The
endpoint therefore needs responder (or admin); the analyst role answers
403, exactly as on decision and release. Splitting it into a label the
analyst may give and a release the responder must confirm was considered and
rejected: a label that does not release is a different product, and one role is
easier to reason about. See roles.
Giving a verdict
Section titled “Giving a verdict”POST /api/v1/incidents/{incident_id}/response-feedbackIf-Match: <the incident's revision>Idempotency-Key: <at least eight characters, unique per attempt>Content-Type: application/json
{"verdict": "false_positive", "note": "Expected vendor telemetry"}verdict is one of the three words above; note is optional and at most 2000
characters. The answer is 201:
{ "id": "rfb_01J...", "incident_id": "inc_01J...", "action_id": "resp_01J...", "verdict": "false_positive", "outcome": "release_expected", "weight": -15, "note": "Expected vendor telemetry", "actor_id": "usr_01J...", "calibration_revision": 1, "created_at": "2026-09-12T12:03:00.000Z", "released_action_ids": ["resp_01J..."], "cancelled_action_ids": [], "calibration": { "…": "the object of GET /api/v1/response/calibration" }}| Field | Meaning |
|---|---|
action_id |
The action the verdict was counted against — the first held action of the incident when there was one; empty otherwise |
outcome, weight |
The outcome the verdict was counted as and its weight; null and 0 for unknown |
released_action_ids, cancelled_action_ids |
What a false_positive set in motion — release requested, not completed |
calibration |
The tenant’s gate after this verdict, the same object the calibration endpoint returns |
Three wire rules, the same as on every other write:
If-Matchis the incident’s revision, not an action’s. A stale value answers409 revision_conflict; re-read the incident and try again. The verdict increases the incident’s revision and lands in itsworkflow_historyasresponse_feedback_<verdict>.Idempotency-Keymakes a retry safe: the same key with the same body returns the stored answer, a different body under the same key is refused. Use a fresh key per attempt, never per incident.- The nonce of the signed request (
X-NDR-Nonce) is single-use until its expiry, as on every write; the dashboard’s BFF mints one per request, and a script that signs its own requests must too.
Any incident can be labelled, not only one that had an action. A confirmed
incident nobody blocked counts as missed_should_block — the heaviest
positive weight, because it is the case the automatic mode exists for.
There is no feedback form in the dashboard yet; the endpoint is the interface. The verdict lands in the incident’s workflow history and, on the Response page, as analyst verdict under the card’s Why block.
Reading the calibration
Section titled “Reading the calibration”GET /api/v1/response/calibration (reader role) returns the tenant’s gate,
read-only:
{ "tenant_id": "example", "configured": true, "learning_until": "2026-09-24T00:00:00.000Z", "learning_active": true, "window_days": 14, "min_labels": 5, "min_precision": 0.8, "true_positives": 3, "false_positives": 1, "unknown": 2, "labels": 4, "distinct_actors": 2, "precision": 0.75, "gate_open": false, "gate_reason": "learning phase until 2026-09-24", "calibration_revision": 1, "last_feedback_at": "2026-09-12T12:03:00.000Z", "updated_at": "2026-09-12T12:03:00.000Z"}| Field | Meaning |
|---|---|
configured |
false until a response target started or feedback was given; the defaults are shown then |
learning_until, learning_active |
The end of the learning phase and whether it is still running; learning_until is null when the phase was switched off with none |
window_days, min_labels, min_precision |
The policy of the response target (calibration_window_days, calibration_min_labels, calibration_min_precision_percent ÷ 100) |
true_positives, false_positives, unknown |
Incidents in the window, each by its latest verdict — five verdicts on one incident are one entry, and a later verdict replaces the earlier one |
labels |
true_positives + false_positives; the count the gate compares against min_labels |
distinct_actors |
How many different people gave the verdicts in the window — reported so a one-person calibration is visible, not gated on |
precision |
true_positives ÷ labels; null without weighted labels |
gate_open, gate_reason |
The verdict and its sentence — the same sentences the Response page and the CLI print |
calibration_revision |
Increases with every verdict; the feedback answer carries the one it produced |
last_feedback_at |
The most recent verdict in this tenant, whether or not it is still inside the window |
The gate is open only after the learning phase, with at least min_labels
labels in the window and precision at or above min_precision;
auto_enabled on the response target is required on top, and the endpoint
does not know whether it is set — the system view
does.
The same state is the calibration line at the top of the Response page.
On the command line
Section titled “On the command line”sudo -u nyxtrace ndr response calibration # every tenant with a calibration rowsudo -u nyxtrace ndr response calibration --tenant examplesudo -u nyxtrace ndr response calibration --json # the objects above, as a listRun it on the appliance as the service user, like every ndr command that
reads the state database. It prints one row per tenant:
TENANT GATE REASON LEARNING UNTIL TP FP UNKNOWN ACTORS PRECISION WINDOW MIN LABELS MIN PRECISION LAST FEEDBACKexample closed learning phase until 2026-09-24 2026-09-24 (active) 3 1 2 2 0.75 14d 5 0.80 2026-09-12T12:03:00ZThe gate opens only after the learning phase, with at least MIN LABELS incidents carrying a true/false-positive verdict in the window (one incident is one label) and PRECISION at or above MIN PRECISION; auto_enabled on the response target is required on top.GATE reads open or closed, with (defaults) appended while no response
target has started and no feedback was given; LEARNING UNTIL is - when the
phase was switched off, (active) while it runs; PRECISION is - without
weighted labels. Without any calibration row the command says so in one
sentence and exits successfully. The gate state is not a health component; the
endpoint and the command are where to read it.
What the numbers do not do
Section titled “What the numbers do not do”- They do not retrain a model, change a threshold or activate anything. A
verdict is input for the gate and, for a
false_positive, a release — and for a triage proposal a person then reads. - They do not calibrate per behaviour signature. The gate is one number per tenant; a precise model and a noisy one share it.
- They do not leave the appliance. Verdicts, notes and actor ids live in the state database and are covered by the backup; none of it is in the telemetry.