Skip to content

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.

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.

POST /api/v1/incidents/{incident_id}/response-feedback
If-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-Match is the incident’s revision, not an action’s. A stale value answers 409 revision_conflict; re-read the incident and try again. The verdict increases the incident’s revision and lands in its workflow_history as response_feedback_<verdict>.
  • Idempotency-Key makes 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.

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.

Terminal window
sudo -u nyxtrace ndr response calibration # every tenant with a calibration row
sudo -u nyxtrace ndr response calibration --tenant example
sudo -u nyxtrace ndr response calibration --json # the objects above, as a list

Run 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 FEEDBACK
example 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:00Z
The 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.

  • 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.