AckdbScoreCriterion

One scoring rule: a field reference + exactly one scoring mode. Field refs — `trait:<key>` / `attribute:<key>` (company grain; person grain: `attribute:is_internal|affiliation_count|key_count`), `identity_link:<type>`, `event:<source>.<bareType>` (aggregate), `contacts` (company grain persona count), `company:trait:<key>` (person grain, best match over ANY active affiliation), `convergence` (both grains: the count of DISTINCT `sources` with activity — or of DISTINCT fired `signals` event refs — inside `windowDays`, scored via `bands`; exactly one of sources | signals).

Properties

groupstringrequired

Key of the group this criterion belongs to.

fieldstringrequired
labelstring

Optional display label for explain/UI.

matcharray of

Value → points entries (first match wins). op: eq | in | present. Legal on value-shaped refs (trait/attribute/identity_link/company:) and, since #438, on `agg: "latest"` event refs: the one aggregate that reduces to a VALUE rather than a volume, so it compares the `valueField` as text where bands/perUnitPoints cast it to numeric. Counting aggregates (count/sum/distinct_contacts) and `contacts` reject match (400), since comparing a count against numbers is what bands is for. Exactly one of match | bands | perUnitPoints(+cap) per criterion. On event metadata the comparison is EXACT and case-sensitive (see /scores/capabilities, `eventValueMatching`): trait values canonicalize case-insensitively (#380), event fields deliberately do not, so seed value pickers from /fields/{key}/values instead of accepting free text.

opstringrequired
"eq""in""present"
valuesarray of
pointsnumberrequiredmin -100 · max 100
bandsarray of

Numeric threshold bands (first match wins). Exactly one of gte/lt per band. Points are ±100, the same bound match entries and perUnitPoints carry.

gtenumber
ltnumber
pointsnumberrequiredmin -100 · max 100
aggstring

Aggregate reducer (event: refs; default count). distinct_contacts is company-grain only. latest (#424) scores the CURRENT value carried in event metadata — the `valueField` of the most recent matching event — instead of a volume.

"count""sum""distinct_contacts""latest"
sumFieldstring

Promoted NUMERIC metadata field — required when agg=sum.

valueFieldstring

Promoted metadata field read off the most recent matching event — REQUIRED when agg=latest, rejected otherwise (#424). Must be promoted on the criterion's event type (entity_events.metadata holds promoted fields only). Its value is cast to numeric; a non-numeric value scores 0 points.

windowDaysintegermin 1 · max 3650

Trailing window; absent = all-time. REQUIRED on convergence, with a tighter 1–365 bound.

halfLifeDaysintegermin 1 · max 3650

Exponential decay half-life (weight = 2^(−age/halfLife)). Not with distinct_contacts or latest.

perUnitPointsnumbermin -100 · max 100

Linear points per unit (with cap).

capnumber

Symmetric clamp for perUnitPoints (0 < cap ≤ 100). Required with it.

filterobject

contacts criterion only: persona filter.

titleContainsarray of
string
activeWithinDaysinteger
sourcesarray of

convergence criterion only: the distinct sources counted (≥2, each must exist in the schema registry). Double counting with per-source `event:` criteria is intended — convergence is the multiplier on top of per-source activity. Exactly one of `sources` | `signals`.

string
signalsarray of

convergence criterion only (#421): user-composed signal list — `event:<source>.<bareType>` refs (2–20, deduped, each must resolve in the schema registry; person grain needs person-scope types). The criterion value is how many listed signals had ≥1 event in the window — a signal firing 40× counts once. Exactly one of `sources` | `signals`.

string

Example

AckdbScoreCriterion example
{
  "group": "string",
  "field": "event:slack.message",
  "label": "string",
  "match": [
    {
      "op": "eq",
      "values": [],
      "points": 0
    }
  ],
  "bands": [
    {
      "gte": 0,
      "lt": 0,
      "points": 0
    }
  ],
  "agg": "count",
  "sumField": "string",
  "valueField": "employee_count",
  "windowDays": 0,
  "halfLifeDays": 0,
  "perUnitPoints": 0,
  "cap": 0,
  "filter": {
    "titleContains": [
      "string"
    ],
    "activeWithinDays": 0
  },
  "sources": [
    "string"
  ],
  "signals": [
    "string"
  ]
}