Skip to content
Docs / Rules found in your history

Rules found in your history

When you build with your past cases, we look for the rules your history already follows and propose them to you, each checked on every past case. Only the ones you confirm are used. Past cases that contradict your rules are flagged for you to review, and aren't learned until you do.

What a found rule shows

They're in the build's found_rules, strongest first, at most 10:

json
{ "id": "fr_1", "sentence": "Escalate refunds over 500", "question": "action", "answer": "escalate",
  "support": 4000, "agreement": 0.97, "status": "proposed", "hard": false, "can_be_hard": true,
  "statement": "Escalate refunds over 500: true in 97% of the 4,000 past cases it applies to.",
  "changes": { "situations": 120, "of": 30000,
               "statement": "Changes 120 of 30,000 situations: approve → escalate." } }
fieldmeaning
sentencethe rule in plain words
question, answerthe question it answers, and the answer it gives where it applies
supportyour past cases it applies to
agreementhow often those cases had its answer
changeswhat confirming it changes in the situations your model learns from
statusproposed (waiting for you: not used), confirmed or rejected
hard, can_be_hardconfirmed as a hard rule; whether it can be one

Only rules your history really shows are proposed: at least 5 cases and 0.5% of them, with at least 80% agreement.

Check each one

A rule found in your history is what you did, not necessarily what you want. Past habits get copied too: a workaround, a policy you've since changed, one team's shortcut. So nothing is used until you decide:

  • Confirm: your model follows it.
  • Confirm as hard (when can_be_hard: it answers the Choice question your hard rules apply to): it's also enforced on every decision, in code, like your own rules, from the retrain it starts.
  • Reject: it isn't used.

changes tells you what confirming it does before you do it. A rule with 97% agreement also means 3% of those cases went the other way: if they were right, reject it, or confirm it and keep those cases when they're flagged.

POST/v1/build/{build_id}/found-rules
curl https://api.canonopylabs.com/v1/build/bld_…/found-rules \
  -H "Authorization: Bearer $CANONOPY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rules": [{"id": "fr_1", "decision": "confirm", "hard": true},
                 {"id": "fr_2", "decision": "reject"},
                 {"id": "fr_3", "decision": "confirm"}]}'

It answers with the Build. This is optional, and nothing waits for it: your model is trained and serves without the found rules, and your decisions apply from the next retrain, with a note that says so. 400: an unknown id, or hard on a rule that can't be hard. 409: the build is busy (queued, building, training or checking); try again when it has finished.

Flagged past cases

A past case that contradicts one of your hard rules, or a found rule you confirmed, is flagged. It's never learned silently: until you review it, it isn't learned at all. The build's flagged has the counts and the first 20:

json
"flagged": { "total": 12, "pending": 12, "items": [
  { "id": "h1042", "state": { "order": { "amount": 820 }, "customer": { "tier": "pro", "fraud_flag": false } },
    "answers": { "action": "approve" }, "rule": "Escalate refunds over 500", "question": "action",
    "rule_answer": "escalate", "kind": "found", "status": "pending",
    "why": "…" } ] }

kind is found (a rule found in your history you confirmed) or hard (one of your hard rules). rule_answer is the rule's answer, or null for a rule that only blocks answers.

GET/v1/build/{build_id}/flagged

All of them, a page at a time: status (pending or reviewed; default all), limit (1-200, default 50) and cursor (the next_cursor of the page before). → build_id, domain, total, pending, items, next_cursor.

POST/v1/build/{build_id}/flagged

For each case:

decisionwhat happens
follow_rulelearn it with the rule's answer (not for a rule that only blocks answers)
keeplearn it as it is: the rule has an exception
dropnever learn it
curl https://api.canonopylabs.com/v1/build/bld_…/flagged \
  -H "Authorization: Bearer $CANONOPY_API_KEY" -H "Content-Type: application/json" \
  -d '{"rows": [{"id": "h1042", "decision": "follow_rule"}, {"id": "h2210", "decision": "drop"}]}'
# or one decision for every case still pending:
curl https://api.canonopylabs.com/v1/build/bld_…/flagged \
  -H "Authorization: Bearer $CANONOPY_API_KEY" -H "Content-Type: application/json" \
  -d '{"all": "follow_rule"}'

→ reviewed, total, pending and a plain-words message. With all: "follow_rule", cases whose rule only blocks answers stay pending: decide those one by one. Your decisions apply when the model is next trained, at the next retrain. Reviewing them is optional: nothing waits on it.

Everywhere

found rulesflagged cases
APIPOST /v1/build/{build_id}/found-rulesGET and POST /v1/build/{build_id}/flagged
CLIcanonopy rules found <model> [--confirm …] [--reject …] [--hard …]canonopy history flagged <model> [--status …] [--follow-rule …] [--keep …] [--drop …] [--all …]
MCPconfirm_found_rules (build_id or model, rules: each id, decision, hard)review_flagged_history (build_id or model; with no decisions it lists the pending ones; rows or all)
Pythonclient.confirm_found_rules(build_id, rules)client.flagged_history(build_id, …), client.review_flagged_history(build_id, rows=…, all=…)
Consolethe build page: Rules found, confirm, reject or hard, each with what it changesthe build page: Flagged history

A coding agent should show each rule and its changes to you and wait for your decision: confirming a rule changes what your model learns, and a hard rule changes what it's allowed to answer.