Overrides and set-asides
Three things get called “accepting a finding” and they mean opposite things about the rule. Keeping them apart is what turns a pile of dismissals into something a compliance lead can act on.
Three things get called accepting a finding
Every other tool in this category files them as one, under a free-text box. Free text conflates all three, and once it has, the dataset is worth nothing: “dismissed 31 times” could mean the rule is broken, the rule is misaimed, or the rule is right and the company published anyway thirty-one times.
- false_positiveThe rule is wrong here
- It matched something it should never match. Evidence about the pattern — thirty of these on one rule is a rule that needs rewriting.
- out_of_scopeThe rule doesn’t apply here
- Correct in general, not applicable to this content. Evidence about the rule’s scope — it is firing somewhere it was never meant to reach.
- accepted_riskShipping anyway
- The rule is right, it applies, and somebody decided to publish. A record of a risk, with a name on it, and never evidence against the rule.
An acceptance therefore requires a class and a reason of at least eight characters — for every class, including accepted_risk, because that is a risk record with somebody’s name on it.
Do not default the choice. Override menus collapse into whichever option is the default click, and once that happens the data is worth nothing. Nothing in this product preselects one, and an integration should not either.
Setting aside is not accepting
A set-aside carries no class and no reason, and sending one with either is refused. Hiding a finding says “not now”, not “not right”: it ranks which rule deserves a look and claims nothing at all about whether that rule is correct.
The distinction is worth a refusal rather than a convention because the two produce opposite conclusions from the same tally. A rule set aside forty times is a rule people keep deferring; a rule accepted as a false positive forty times is a rule that is wrong. A system that let one be recorded as the other would produce a report that reads plausibly and points at the wrong rule.
A set-aside is still recorded. It is in the ledger and it is in the release record — the record names every finding including the ones set aside, because a record describing a tidied version of the content would be worthless.
What each override records
The row is written once and cannot be updated or deleted, by anyone. Several of its columns are snapshots rather than references, and that is the design.
- The rule’s wording
- Copied in, not looked up. Rules are editable, so a report resolving ids against today’s text would attribute a year of dismissals to whatever the rule was rewritten to say last week.
- The tier
- An acceptance on a reviewed finding is evidence about the model; on a verified finding it is evidence about the rule. Kept as a column so the two can never be pooled by whatever reads this next.
- The excerpt
- What matched. For several rule kinds the checker generates it — “Reading level is grade 11.2” — rather than quoting content.
- The whole field
- The surrounding text, kept because the excerpt alone is not enough to judge a rule by. Anything reasoning from excerpts alone would be reasoning about this application’s own log messages.
- The hand
- Who made the call, and which brand and campaign it was in. A judgement about a rule is filed against the brand, because that is what decides tenancy; the campaign is recorded too, because “this rule keeps misfiring on the Q3 launch” is a real thing to be able to see.
What comes out the other end is a fact a compliance lead cannot discover today by any means: this rule fired forty times and was dismissed as a false positive thirty-one of them, twenty-two by the same person. That needs no model to produce, which is why the ledger was built before anything that learns from it.
Recording one from your own tool
An override taken in a Figma plugin and an override taken in the studio land in the same ledger, under the same rules, in one audit trail. That is what makes an integration worth building rather than a lint pass — a compliance lead does not want five tools’ worth of overrides.
POST /functions/v1/disposition
x-api-key: cs_live_…
{
"workspaceId": "8f2c…",
"disposition": "accepted",
"acceptClass": "false_positive",
"reason": "Matched 'specialist equipment', not a person.",
"ruleId": "pharma-cure",
"ruleKind": "banned_phrase",
"tier": "verified",
"severity": "block",
"location": "Frame 3 · title",
"excerpt": "cure",
"fieldText": "A cure for chronic fatigue.",
"externalRef": { "file": "abc123", "node": "12:445" }
}{
"workspaceId": "8f2c…",
"disposition": "hidden",
"ruleId": "pharma-cure",
"location": "Frame 3 · title"
}It needs the dispose scope, which is narrower than review and granted separately. tier and severity are refused rather than coerced if they are not values the engine uses: a record that quietly says something other than what the caller asserted is worse than one that made them say it again.
Nothing is recorded about the person. The actor field is left null and the key’s name is stored instead, because that is the truth of it — the account knows an override came through your integration and does not know who was in front of it. There is no field for a user id, deliberately: accepting one would let any key holder put a colleague’s name on a decision they never made, which in a compliance record is worse than no name at all. Per-person attribution goes in externalRef, where it is plainly your claim rather than the account’s record.
location is part of a finding’s identity and overrides are keyed to it, so changing your location strings later detaches every override already recorded against them. The full request shape is beside the check itself on the review API.